mv
整理が必要なファイルが100万個以上あるフォルダがあるのですが、このメッセージが常に表示されるため、何もできません。
-bash: /bin/mv: Argument list too long
拡張子のないファイルを移動するために次のコマンドを使用しています:
mv -- !(*.jpg|*.png|*.bmp) targetdir/
答え1
xargs
仕事のためのツールです。あるいはfind
-exec … {} +
これらのツールは、一度に渡せる数の引数を使用して、コマンドを複数回実行します。
どちらの方法も、可変引数リストが最後にある場合は実行が簡単になりますが、ここではそうではありません。 の最後の引数はmv
宛先です。 GNU ユーティリティ (つまり、非組み込み Linux または Cygwin) では、-t
のオプションがmv
、宛先を最初に渡すために役立ちます。
ファイル名に空白や が含まれず\"'
、¹ で始まっていない場合は-
、 への入力としてファイル名を指定するだけですxargs
(echo
コマンドは bash の組み込みコマンドなので、コマンド ラインの長さ制限は適用されません。 が表示される場合は!: event not found
、 を使用してグロブ構文を有効にする必要がありますshopt -s extglob
)。
echo !(*.jpg|*.png|*.bmp) | xargs mv -t targetdir --
-0
オプションをxargs
使用すると、デフォルトの引用符形式の代わりに null 区切りの入力を使用できます。
printf '%s\0' !(*.jpg|*.png|*.bmp) | xargs -0 mv -t targetdir --
あるいは、 を使用してファイル名のリストを生成することもできますfind
。サブディレクトリへの再帰を避けるには、 を使用します-type d -prune
。リストされたイメージ ファイルに対してアクションが指定されていないため、他のファイルのみが移動されます。
find . -name . -o -type d -prune -o \
-name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o \
-exec mv -t targetdir/ {} +
(シェルのワイルドカード方式とは異なり、ドット ファイルも含まれます。)
GNU ユーティリティがない場合は、中間シェルを使用して引数を正しい順序で取得できます。この方法は、すべての POSIX システムで機能します。
find . -name . -o -type d -prune -o \
-name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o \
-exec sh -c 'mv "$@" "$0"' targetdir/ {} +
zshでは、mv
組み込み:
setopt extended_glob
zmodload zsh/files
mv -- ^*.(jpg|png|bmp) targetdir/
mv
または、やその他の名前で外部コマンドを参照し続けたい場合は、次のようにします。
setopt extended_glob
zmodload -Fm zsh/files b:zf_\*
zf_mv -- ^*.(jpg|png|bmp) targetdir/
またはkshスタイルのglobを使用する場合:
setopt ksh_glob
zmodload -Fm zsh/files b:zf_\*
zf_mv -- !(*.jpg|*.png|*.bmp) targetdir/
あるいは、GNUmv
とzargs
:
autoload -U zargs
setopt extended_glob
zargs -- ./^*.(jpg|png|bmp) -- mv -t targetdir/ --
¹xargs
実装によっては、ファイル名も現在のロケールで有効なテキストでなければなりません。ファイル名が_
入力の終わりを示すものと見なされる場合もあります ( で回避できます-E ''
)
答え2
Linuxカーネルで作業するだけで十分な場合は、次のようにします。
ulimit -S -s unlimited
これは、Linux カーネルに約 10 年前にスタック サイズに基づいて引数の制限を変更するパッチが含まれていたため機能します。https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b6a2fea39318e43fee84fa7b0b90d68bed92d2ba
無制限のスタックスペースが必要ない場合は、例えば次のようにします。
ulimit -S -s 100000
スタックを 100 MB に制限します。スタック領域を通常のスタック使用量 (通常は 8 MB) と使用するコマンド ラインのサイズに設定する必要があることに注意してください。
実際の制限は次のように照会できます。
getconf ARG_MAX
コマンドラインの最大長をバイト単位で出力します。たとえば、Ubuntuのデフォルトでは、これは2097152
約2MBです。無制限のスタックで実行すると、4611686018427387903
これはちょうど2^62、つまり約46000TBになります。コマンドラインがそれ、あなた自身で問題を回避できることを期待しています。
実行sudo
中に を使用すると、 が実際に実行する前にスタック サイズをリセットするため、この問題を修正できないことに注意してください。これを回避するには、 を使用してルート シェルを開始し、 を実行して、最後にそのルート シェルで を使用せずにコマンドを実行する必要があります。sudo mv *.dat somewhere/.
ulimit
sudo
mv
sudo -s
ulimit -S -s unlimited
sudo
答え3
場合によっては、Python などの小さなスクリプトを書くのが最も簡単なこともあります。
import glob, shutil
for i in glob.glob('*.jpg'):
shutil.move(i, 'new_dir/' + i)
答え4
xargs
オペレーティング システムの引数渡し制限は、シェル インタープリタ内で行われる展開には適用されません。したがって、またはを使用するだけでなくfind
、シェル ループを使用して処理を個々のコマンドに分割することもできますmv
。
for x in *; do case "$x" in *.jpg|*.png|*.bmp) ;; *) mv -- "$x" target ;; esac ; done
これは POSIX シェル コマンド言語の機能とユーティリティのみを使用します。このワンライナーはインデントによりわかりやすくなり、不要なセミコロンが削除されています。
for x in *; do
case "$x" in
*.jpg|*.png|*.bmp)
;; # nothing
*) # catch-all case
mv -- "$x" target
;;
esac
done