このコマンドを使用するとmv * ..
エラーが発生します-bash: /usr/bin/mv: Argument list too long
。私はこれが起こる理由は、bashが実際に一致する各ファイルにアスタリスクを拡張して非常に長いコマンドラインを生成するためであることを知っています。このエラーをどのように解決できますか?
答え1
制限は bash にあるのではなく、execve()
外部コマンドの実行に使用されるシステム呼び出しにあります。次のことができます。
printf '%s\0' * | xargs -r0 mv -t .. --
printf
内蔵されているので現在bash
はありません。この制限を回避するには、パラメータリストを分割するexecve()
必要があります。 GNUのGNU固有のオプションがxargs
ここで使用されます。-t
mv
を使用すると、組み込みアイテムをzsh
読み込むことができます。mv
zmodload zsh/files
mv -- * ..
または、zargs
ヘルパーを使用して分割を実行します。
autoload -Uz zargs # best in ~/.zshrc
zargs -r -- ./* -- mv -t ..
withを置き換え./*
て./*(D)
隠しファイルを移動したり、oN
glob修飾子を追加してファイル名の並べ替えをスキップしたり、N
glob修飾子(with 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()
計算は単にバイト合計以上であり、実行方法はオペレーティングシステムとバージョンによって異なります。
答え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 {} +
これらのバリエーションのどれも名前の衝突に興味がありません。正しくバックアップされたデータでテストする必要があります。