一連のディレクトリを一度にプッシュする方法は?

一連のディレクトリを一度にプッシュする方法は?

foo私はサブディレクトリを含むディレクトリにあり、bar1 bar2それがbar3すべてです。

pushd、およびをfoo1つのコマンドで実行したいのですが、停止しました。bar1bar2bar3

find `pwd` | xargs pushd

返品

xargs: pushd: No such file or directory

この問題を回避するためにwhileループを使用してみました。

find `pwd` | while read line ; do pushd $line ; done

これにより、正しく表示される出力が提供されます。

~/foo ~/foo
~/foo/bar1 ~/foo ~/foo
~/foo/bar2 ~/foo/bar1 ~/foo ~/foo
~/foo/bar3 ~/foo/bar2 ~/foo/bar1 ~/foo ~/foo

しかし、後でこれを使用すると、スタックdirsに新しいディレクトリを追加していないことがわかります。

~/foo

何が間違っているのかを理解できる人はいますか?

答え1

あなたは非常に近いです。欲しいことができます

while read line; do pushd "$line"; done < <(find "$(pwd)" -type d)

コマンドの問題は、有用な場合は基本(親)プロセスでpushd実行するcd必要があり(システムの設定方法によって若干の違いがある)、パイプラインのコマンドが子プロセス(子プロセス)で実行されることです。 )。パイプを与えずに魔法のようにパイプを与えます。< <(cmd)

POSIXは 。<(cmd)

残念ながら、このxargsアプローチは失敗する運命です。なぜならpushd(like cd)はシェル組み込み(つまり、プログラムpushd)と呼ばれ、xargs外部実行プログラムが必要です。以下を使用して(ほぼ)正しく表示される出力を取得できます。

$ find "$(pwd)" -type d | xargs -i sh -c 'pushd "$1"' sh
~/foo ~/foo
~/foo/bar1 ~/foo
~/foo/bar2 ~/foo
~/foo/bar3 ~/foo

ただし、これはシェルを外部プログラムとして実行し、各ディレクトリに対して(独立して)これを行います。これはやや近いです。

$ find "$(pwd)" -type d | xargs sh -c 'for line do pushd "$line"; done' sh
~/foo ~/foo
~/foo/bar1 ~/foo ~/foo
~/foo/bar2 ~/foo/bar1 ~/foo ~/foo
~/foo/bar3 ~/foo/bar2 ~/foo/bar1 ~/foo ~/foo

単一のシェルプロセスを実行し、すべてのディレクトリを繰り返すように指示します。ご覧のとおり、この手法は2回目の試み(および私の答え)に似ており、結果は2回目の試みと同じです。pushd4回呼び出される新しいシェルプロセスが取得され、最終的にAディレクトリスタックが作成されます。つまり、5つのレベルの深さ(開始ディレクトリを2回計算) - しかし、新しいシェルプロセスは子プロセスにあり、次のシェルプロンプトが表示された場合それシェルプロセスが消えた。

ちなみに、コマンドは次のように似ています。 私が数年前にした答えは。  スティーブン・チャジェラスコマンド構造の議論 sh -c long_complex_shell_command shここそしてここ

答え2

これは仕事ではありませんfind

for subdirectory in */; do
  pushd -- "$subdirectory"
done

pushdたとえば、cd影響を与えるシェル環境でコードを実行する必要があるため、コードは機能しません。pushd外部コマンドには意味がないため、呼び出すことができるxargs外部コマンドはありません。何の影響もありません。パイプの右側はサブシェルで実行されます(シェルの内側には他のシェルで実行されているいくつかのシェルがあり、2番目の試みが機能していることがわかります)pushd

find `pwd` | {
  while read line ; do pushd $line ; done;
  dirs
}

ディレクトリ名に特殊文字が含まれていない場合は有効です。変数置換を削除する理由がわからない限り、必ず変数置換の周りに二重引用符を入れてください。

関連情報