5

ディレクトリ~/temp/a/foo/には、、、、などの名前の~/temp/b/foo foo/ファイルがいくつかあります。bar1bar2bar bar1bar bar2

名前の最後の部分として「foo」を含むディレクトリ内のこれらすべてのファイルを、それぞれの「foo」フォルダーの上のフォルダーにコピーする Bash の行を書き込もうとしています。

ファイル名にスペースが含まれていない限り、これは簡単な作業ですが、foo fooディレクトリを処理するときに次の 2 つのコマンドが失敗します。

for dir in `find . -type d -name '*foo'` ; do cp $dir/* "$(echo $dir|sed 's_foo__g')" ; done

(cpコマンドは、最後fooの を"foo foo"同じディレクトリ名の一部として認識できません。)

for dir in `find . -type d -name '*foo'` ; do cp "$dir/*" "$(echo $dir|sed 's_foo__g')" ; done

("$dir/*"展開されていません。)

で置き換えるなどの試みは、さらに成功していません$dir/*"$(echo $dir/*)"

理解できる$dir/*ように展開する簡単な方法はありますか?cp

4

3 に答える 3

4

forループが間違っているだけでなくsed、このジョブに適したツールでもありません。

while IFS= read -r -d '' dir; do
  cp "$dir" "${dir/foo/}"
done < <(find . -type d -name '*foo' -print0)

(および)で使用-print0すると、改行を含むファイル名が混乱することはありません。findIFS= read -r -d ''

構造を使用する< <(...)と、ループの内部で変数を設定したり、ディレクトリの状態を変更したり、同様のことを行ったりしても、それらの変更は存続します(パイプラインの右側は、bashのサブシェルにあるため、whileループにパイプすることでそのwhileループ内で行われたシェルの状態への変更は、それ以外の場合は終了時に破棄されることを意味します)。

使用は、bashの内部で文字列の置換を行うため${dir/foo/}、呼び出すよりもはるかに効率的です。sed

于 2013-03-16T23:36:56.047 に答える
2

ここでの問題は ではなくcpですfor。デフォルトでは、サブシェルの出力がディレクトリ名ではなく単語で分割されるためです。

怠惰な回避策は、while代わりに使用して、次のようにディレクトリのリストを 1 行ずつ処理することです。

find . -type d -name '*foo' | while read dir; do cp "$dir"/* "$(echo $dir | sed 's_foo__g')" ; done

これでスペースの問題は解決するはずですが、これは決して確実な解決策ではありません。

より正確な解決策については、Charles Duffy の回答を参照してください。

于 2013-03-16T23:28:15.013 に答える
0

~/temp/b/foo foo/スペースのないものに名前を変更します。たとえば~/temp/b/foo_foo/、もう一度やろうとしていたことを実行します。その後、本当に必要な場合は、スペースを入れて元の名前に戻すことができます。ところで。私自身、あなたが今直面しているような複雑さを避けるために、スペースを含むファイル名を使用することはありません.

于 2013-03-16T23:13:30.127 に答える