「mv:パラメータリストが多すぎる」問題を解決しますか?

「mv:パラメータリストが多すぎる」問題を解決しますか?

mv並べ替える必要があるファイルが100万以上あるフォルダがありますが、このメッセージが引き続き出力されるため、何もできません。

-bash: /bin/mv: Argument list too long

拡張子なしでファイルを移動するには、次のコマンドを使用します。

mv -- !(*.jpg|*.png|*.bmp) targetdir/

答え1

xargs作業のためのツールです。それ、またはfindそして-exec … {} +。これらのツールはコマンドを複数回実行して、一度にできるだけ多くのパラメータを渡します。

どちらの方法も、可変引数リストが最後にあるときに実行する方が簡単ですが、ここではそうではありません。最後の引数がmvターゲットです。 GNUユーティリティ(つまり、組み込まれていないLinuxまたはCygwin)の場合、-tこのオプションはターゲットをmv最初に渡すのに役立ちます。

ファイル名にスペースや\"'スペースが含まれ-ておらず、1で始まらない場合は、ファイル名を入力として指定するだけです(xargsコマンドはbashに組み込まれているため、コマンドラインの長さ制限は適用されechoません)。ワイルドカード構文を有効にします。!: event not foundshopt -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または let と他の名前が外部コマンドを参照し続けたい場合:

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/

またはGNUを使用mvして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

スタックを100MBに制限します。スタックスペースを通常のスタック使用量(通常8 MB)に使用するコマンドラインサイズを加算した値に設定する必要があります。

以下で実際の制限を確認できます。

getconf ARG_MAX

これにより、最大コマンドライン長がバイト単位で出力されます。たとえば、Ubuntuのデフォルト値は2097152約2MBです。無限スタックで実行すると得られるサイズは4611686018427387903正確に2^62または約46000TBです。コマンドラインが次を超える場合それ、問題を直接解決できることを願っています。

asをすぐに使用すると、sudo実際の実行前にスタックサイズがリセットされるため、問題を解決できません。この問題を解決するには、を使用してルートシェルを起動して実行し、最後にルートシェルでコマンドを実行せずにコマンドを実行する必要があります。sudo mv *.dat somewhere/.ulimitsudomvsudo -sulimit -S -s unlimitedsudo

答え3

時には最も簡単な方法はPythonのような小さなスクリプトを書くことです。

import glob, shutil

for i in glob.glob('*.jpg'):
  shutil.move(i, 'new_dir/' + i)

答え4

オペレーティングシステムのパラメータ転送制限は、シェルインタプリタ内で発生する拡張には適用されません。したがってxargs、orを使用する代わりに、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

関連情報