このコマンドを使用するとmv * ..
、エラーが発生します-bash: /usr/bin/mv: Argument list too long
。これが発生する理由は、bash が実際にアスタリスクをすべての一致するファイルに展開し、非常に長いコマンド ラインを生成するためだと理解しています。このエラーを修正するにはどうすればよいですか?
答え1
制限は bash ではなく、execve()
外部コマンドを実行するために使用されるシステム コールにあります。次のように実行できます。
printf '%s\0' * | xargs -r0 mv -t .. --
printf
は に組み込まれているため、その時点ではbash
はありません。そして、その制限を回避するために引数のリストを分割することが の仕事です。ここでは、GNU のGNU 固有のオプションを使用しています。execve()
xargs
-t
mv
を使用するとzsh
、組み込みをロードできますmv
。
zmodload zsh/files
mv -- * ..
または、zargs
ヘルパーを使用して分割を実行します。
autoload -Uz zargs # best in ~/.zshrc
zargs -r -- ./* -- mv -t ..
./*
を に置き換え./*(D)
て隠しファイルも移動したり、oN
glob 修飾子を追加してファイル名のソートをスキップしたり、N
glob 修飾子 ( を使用zargs -r
) を追加して一致するファイルがない場合にエラーを回避したりすることもできます。
zargs -r -- ./*(ND) -- mv -t ..
と同じ:
print -rNC1 ./*(ND) | xargs -r0 mv -t ..
ただし、 GNU への依存性はありませんxargs
。
Linux (Ubuntu で一般的に使用されるカーネル) では、リソース制限execve()
を上げることでその制限を上げることもできますstacksize
。
bash-5.1$ /bin/true {1..200000}
bash: /bin/true: Argument list too long
bash-5.1$ ulimit -s unlimited
bash-5.1$ /bin/true {1..200000}
bash-5.1$
完全に無制限というわけではありません (少なくともカーネルの現在のバージョンではそうではありません)。
bash-5.1$ /bin/true {1..2000000}
bash: /bin/true: Argument list too long
制限は、 に渡される引数と環境変数の合計サイズにありますexecve()
が、計算は単にバイトの合計ではなく、その方法は OS とそのバージョンによって異なります。
答え2
2 つ以上のステップで実行できます。
mv [a-k]* .. # or some other pattern matching a subset of the files
mv -- * ..
あるいはループで、
for name in *; do
mv -- "$name" ..
done
(ただし、これにはmv
それぞれの名前が個別に必要になります。)
または、次のfind
方法でお手伝いします:
find . -mindepth 1 -maxdepth 1 -exec mv -t .. -- {} +
これにより、現在のディレクトリ内のすべての名前が検索され、GNU を使用して、 の呼び出しをできるだけmv
少なくして、それらの名前が上のディレクトリに移動します。mv
GNU はなくてmv
も、find
非標準の述語-mindepth
と-maxdepth
述語を認識している があれば、
find . -mindepth 1 -maxdepth 1 -exec sh -c 'mv -- "$@" ..' sh {} +
これらのバリエーションはいずれも名前の衝突を気にしません。適切にバックアップされたデータでテストする必要があります。