サブシェルを使用せずにシェルコマンドの置き換えを実行できますか?

サブシェルを使用せずにシェルコマンドの置き換えを実行できますか?

サブシェルを使用せずにコマンド置換が必要なシナリオがあります。私は次の構造を持っています:

pushd $(mktemp -d)

今、一時ディレクトリを一度に終了して削除したいと思います。

rmdir $(popd)

popdただし、ポップされたディレクトリは返されず(新しい現在のディレクトリが返されます)、サブシェルで実行されるため機能しません。

それはまるで

dirs -l -1 ; popd &> /dev/null

ポップされたディレクトリを返しますが、次のようには使用できません。

rmdir $(dirs -l -1 ; popd &> /dev/null)

popdサブシェルにのみ影響するからです。必要なのはこれを行う能力です。

rmdir { dirs -l -1 ; popd &> /dev/null; }

しかし、これは間違った構文です。そのような効果を得ることができますか?

(注:一時ディレクトリを変数に保存できることを知っています。

ベストアンサー1

あなたの質問のタイトルの選択は少し混乱しています。

pushd/はコピー機能でpopdあり、記憶されたディレクトリを管理する方法です。cshbashzsh

pushd /some/dir

宣伝する現在の作業ディレクトリをスタックに追加し、それから現在の作業ディレクトリを変更してから、/some/dirそのスタックの内容を印刷します(スペースで区切ります)。

popd

スタックの内容を空白で区切って印刷し、スタックの最上位要素に変更してスタックからポップします。

~/x(また、いくつかのディレクトリはまたは記号で表示されます~user/x。)

したがって、スタックに現在のディレクトリがあり、/a現在の/bディレクトリがあり、/here実行中の場合:

 pushd /tmp/whatever
 popd

pushd代わりに印刷し/tmp/whatever /here /a /bpopd印刷します。これは、コマンド置換を使用するかどうかには関係ありません。古いディレクトリへのパスを取得するために使用することはできず、その出力は通常後処理できません(ディレクトリスタックの要素にアクセスするには、一部のシェルまたは配列を参照してください)。/here /a /b/tmp/whateverpopd$dirstack$DIRSTACK

おそらくあなたは以下が欲しいでしょう:

pushd "$(mktemp -d)" &&
popd &&
rmdir "$OLDPWD"

または

cd "$(mktemp -d)" &&
cd - &&
rmdir "$OLDPWD"

しかし、私は以下を使用します:

tmpdir=$(mktemp -d) || exit
(
  cd "$tmpdir" || exit # in a subshell 
  # do what you have to do in that tmpdir
)
rmdir "$tmpdir"

いずれにせよ、サブシェルでは実行されpushd "$(mktemp -d)"ません。pushdその場合、作業ディレクトリを変更することはできません。これはmktempサブシェルで実行されます。別のコマンドなので、別のプロセスで実行する必要があります。出力をパイプに書き込み、シェルプロセスはパイプのもう一方の端からそれを読み取ります。

ksh93はコマンドが組み込まれたときに別々のプロセスを避けることができますが、そこにはまだサブシェル(他の作業環境)があり、今回は通常フォークで提供される別の環境に依存せずにエミュレートされます。たとえば、ksh93分岐a=0; echo "$(a=1; echo test)"; echo "$a"は含まれませんが、出力はまだecho "$a"存在します0

mktempここでの出力をに渡して変数に保存するには、次のようにしますpushdzsh

pushd ${tmpdir::="$(mktemp -d)"}

他のBourneに似たシェルの場合:

unset -v tmpdir
pushd "${tmpdir=$(mktemp -d)}"

あるいは、出力を$(mktemp -d)変数に明示的に保存せずに複数回使用する場合は、zsh匿名関数を使用できます。

(){pushd ${1?} && cd - && rmdir $1} "$(mktemp -d)"

おすすめ記事