web-dev-qa-db-ja.com

一連のディレクトリを一度にプッシュするにはどうすればよいですか?

私は、サブディレクトリbar1bar2bar3を含むディレクトリfooにいます。

1つのコマンドでpushdbar1bar2、およびbar3に対してfooを実行したいのですが、問題が発生しています。

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

誰かが私が間違っていることを見つけることができますか?

2
Miguel

あなたはとても近くにいます。あなたはあなたがやりたいことをすることができます

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

コマンドの問題は、pushdと同様に、cdを使用するには、メイン(親)プロセスで実行する必要があることです(システムの設定方法によって多少異なります)。 、パイプライン内のコマンドはサブプロセス(子プロセス)で実行されます。 < <(cmd)は、パイプラインを提供せずに魔法のようにパイプを提供します。

POSIXは<(cmd)をサポートしていないため、これにはbash(または他の高度なシェルの1つ?)を実行している必要があります。

残念ながら、xargspushdなど)はシェルの組み込みコマンドであるため、cdアプローチは失敗する運命にありました(つまり、programpushd)と呼ばれ、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回目の試行と同じです。pushdを4回呼び出す新しいシェルプロセスを取得し、最終的には5レベルの深さのディレクトリスタック(開始ディレクトリを2回カウント)を使用しますが、その新しいシェルプロセスはサブプロセス内にあり、次のシェルプロンプトが表示されるまでに、thatシェルプロセスがなくなりました。

参考までに、このコマンドは 数年前に私が出した答え にいくぶん似ていることに注意してください。 StéphaneChazelas _sh -c long_complex_Shell_command sh_コマンド構造について説明します ここ および ここ

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

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

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

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

ディレクトリ名に特殊文字が含まれていない限り、つまり機能します。 変数の置換を省略する必要がある理由がわからない限り、変数の置換は常に二重引用符で囲みます