サブフォルダ内のすべてのファイルを現在のフォルダに移動するには、このスクリプトを使用します。
while read f
do
mv "$f" .
done < file_list
file_list
これはうまく機能しますが、生成する必要があります
find . -name *.avi > file_list
私が望むのは、コマンドをwhileループに直接追加することです。
while read f
do
mv "$f" .
done < find . -name *.avi
しかし、バッシュは私に言う -bash: syntax error near unexpected token `.'
findコマンドをwhileループにパイプする簡単な解決策は何ですか?
答え1
これにはループは必要なく、find
次のように実行できます。
find . -name '*.avi' -exec mv {} . \;
答え2
プロセス置換を使用することもできます。
while IFS= read -r f
do
mv -- "$f" .
done < <(find . -name '*.avi' )
シェルでは、bash
パイプライン方式と比較して利点があります。いいえサブシェルでループを実行すると、ループ内で行った変数の割り当ては後で失われません。bash
(または)では、zsh
次のことをお勧めします。
while IFS= read <&3 -rd '' f
do
mv -- "$f" .
done 3< <(find . -name '*.avi' -print0)
任意のファイル名を処理するには、NUL区切り文字を使用し、ユーザーにプロンプトが表示され、stdinから答えを読むことができるので、0の代わりにfd 3を使用してください。mv
これは0を使用した場合に出力になります。find
または、find
コマンド自体を使用します。
find . -name '*.avi' -exec mv -t . {} +
使用する+
ことは、多くのパラメータを一度に渡すので、各ファイルmv
に対してmv
呼び出しを実行する必要がないという意味です。-t
GNU拡張です。他のmv
実装では、次のように変更できます。
find . -name '*.avi' -exec sh -c 'exec mv "$@" .' sh {} +
答え3
正しい方法はパイプです
find . -name '*.avi' |
while read f
do
mv "$f" .
done
第1のコマンド「」の結果は、find . -name *.avi
第2のコマンドに提供される。
これをパイプといいます(記号に由来|
)。パイプを次の一時ファイルとして考えることができます。
find . -name '*.avi' > file1.tmp
while read f
do
mv "$f" .
done < file1.tmp
rm file1.tmp
指摘したように、ファイル名にスペースまたは改行文字が含まれると、エラーが発生する可能性があります。
唯一の目的がファイルを移動することである場合は、@Terdonのコマンドを使用してください。
また、引用する必要があります。*.avi
それ以外の場合は、2回目の実行で中断されます。
find: paths must precede expression: `foo.avi'
find: possible unquoted pattern after predicate `-name'?
答え4
既存の2つの答えの間の中間位置は、「インライン」を見つけて使用することです。~のためリングの形。
for f in `find . -name '*.avi' `
do
mv "$f" .
done
バックティックを使用すると、findコマンドが所定の位置で実行され、その出力が置き換えられます。
欠点ファイル名に空白と予期しない奇妙な文字が含まれていると、問題が発生する可能性があります。 @Terdonの答えは素晴らしいです。