約280,000個のファイルを含むディレクトリがあります。別のディレクトリに移動したい。
cp
またはmv
を使用すると、「引数リストが長すぎます」というエラーが表示されます。
次のようなスクリプトを書いた場合
for file in ls *; do
cp {source} to {destination}
done
次に、ls
コマンドが原因で、そのパフォーマンスが低下します。
これどうやってするの?
ここでは答えに2つのツインクが欠けているので、さらに1つ追加します。
これは私にさらに別の追加を思い出させますが 標準 回答...
ここには2つの問題があります。
約280,000個のファイルを含むディレクトリがあります。
ほとんどのツールは、この数のファイルではそれほどうまくスケーリングしません。ほとんどのLinuxツールやWindowsツールだけでなく、多くのプログラム。そしてそれはあなたのファイルシステムを含むかもしれません。長期的な解決策は、「まあ、そうしないでください」でしょう。異なるファイルがあるが、それらは異なるディレクトリにある場合。将来的に問題が発生し続けると予想されない場合。
それでは、実際の問題に移りましょう:
Cpまたはmvを使用すると、「引数リストが長すぎます」というエラーが表示されます
これは、シェルによる*の拡張が原因です。シェルには結果用のスペースが限られているため、スペースが足りなくなります。つまり、シェルによって*
が展開されたコマンドはすべて同じ問題に遭遇します。同時に展開するオプションの数を減らすか、別のコマンドを使用する必要があります。
この問題が発生したときによく使用される代替コマンドは、find
です。それを使用する方法を示すいくつかの回答がすでにあるので、私はそれをすべて繰り返すつもりはありません。ただし、\;
と+
の違いを指摘しておきます。これにより、パフォーマンスに大きな違いが生じ、前の拡張の説明にうまく結び付く可能性があるためです。
find /path/to/search --name "*.txt" -exec command {} \;
Path/to/search /の下にあるすべてのファイルを検索し、それを使用してコマンドを実行しますが、*
を囲む引用符に注意してください。これは*をコマンドに送ります。それをカプセル化またはエスケープしなかった場合、シェルはそれを拡張しようとし、同じエラーが発生します。
最後に、{}についてお話します。これらの括弧は、findで見つかったコンテンツに置き換えられます。コマンドをセミコロン;
(シェルからエスケープする必要があるため、例では\;
がある)でコマンドを終了すると、結果は1つずつ渡されます。つまり、280000 mvコマンドを実行します。ファイルごとに1つ。これは遅いかもしれません。
または、+
で終わることもできます。これは、できるだけ多くの引数を同時に渡します。 bashが2000個の引数を処理できる場合、/ path -name "* filetype" -exec some_move {} +はsome_moveコマンドを約140回、毎回2000個の引数で呼び出します。それはより効率的です(読む:より速く)。
(コピーではなく)移動する場合はどうですか?
$ find {Origin}/ -maxdepth 1 -name "*" -o -name ".*" -exec mv '{}' {destination}/ ';'
これは、構造(サブディレクトリ)と隠しファイルまたはディレクトリを保持したまま移動し、さらにrsync + rmの場合のように余分なスペースが消費されることはないと思います。また、{Origin}と{destination}が同じパーティションにある場合は、より高速になります。
あなたはlsを必要としません、あなたは単に使うことができます
for file in *; do
cp $file /your/dest
done
またはあなたは次のようなことをすることができます:
echo * | xargs -i cp {} /your/dest
Tarを使用:
(cd {Origin}; tar cf - .)|(cd {destination}; tar xvf -)
Originが最初はrsyncに対して大きすぎるが、デルタはそうではないときに、物事を始めるのに役立ちます。
同じファイルシステム内でファイルを移動したい場合、lacsを含むディレクトリの名前を変更するだけで済みます。
私の場合、cp
とrsync
はどちらも、HDDからSSDに約400万個のファイルをコピーするには遅すぎたので、以下にその方法を示します(すべてのファイルは.txtファイルでした。同じフォルダなので、find
を調整してください):
cd /path/to/source/folder
find . -name '*.txt' -print >/tmp/test.manifest
tar -c -T /tmp/test.manifest | (cd /path/to/destination/folder; tar xfp -)
Argument list too long
エラーが発生したため、ファイル名を一時ファイルに出力する必要がありました。 tar
を使用すると、転送速度が大幅に向上しましたが、圧縮が容易でないファイルも同様に機能しない可能性があると思います。
#!/bin/bash
d=$(date +%Y%m%d%H%m%s)
cd /path
tar zcvf "/destination/bakup_${d}.tar.gz" mydirectory_for_transer
私はこれのためにrsync
が好きです、または:
find dir1 -type f -exec cp {} dir2 \;