回答:
xargs
仕事のためのツールです。それか、find
と-exec … {} +
。これらのツールは、一度に渡すことができる限り多くの引数を使用して、コマンドを数回実行します。
両方の方法は、変数引数リストが最後にある場合に実行しやすくなりますが、ここではそうではありませんmv
。最終的な引数は宛先です。GNUユーティリティ(つまり、非組み込みLinuxまたはCygwin)では、宛先を最初に渡す-t
オプションmv
が便利です。
ファイル名に空白やが含まれていない場合は\"'
、ファイル名を入力として単純に提供できますxargs
(echo
コマンドはbashビルトインであるため、コマンドラインの長さの制限を受けません)。
echo !(*.jpg|*.png|*.bmp) | xargs mv -t targetdir
この-0
オプションを使用してxargs
、デフォルトの引用形式の代わりにヌル区切りの入力を使用できます。
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/
またはlet mv
および他の名前が外部コマンドを参照し続ける場合:
setopt extended_glob
zmodload -Fm zsh/files b:zf_\*
zf_mv -- ^*.(jpg|png|bmp) targetdir/
またはkshスタイルのグロブを使用する場合:
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/
shopt -s extglob
有効にする必要があります。find
コマンドのステップを見逃していたので、修正しました。
find
コマンド(現在)は動作します。コピー&ペーストするときは、一部を中断している必要があります。
!
ですか?奇数の末尾よりも明確で理解しやすい-o
です。たとえば、! -name '*.jpg' -a ! -name '*.png' -a ! -name '*.bmp'
Linuxカーネルでの作業で十分な場合は、単に行うことができます
ulimit -s 100000
これは、Linuxカーネルに約10年前にスタックサイズに基づいて引数の制限が変更されたパッチが含まれているため機能します。https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit /?id = b6a2fea39318e43fee84fa7b0b90d68bed92d2ba
更新:勇気があるなら、あなたは言うことができます
ulimit -s unlimited
また、十分なRAMがあればシェルの拡張でも問題ありません。
ulimit -s unlimited
、実質的に無制限のファイルに対して機能します。
ulimit -s unlimited
、実際のコマンドラインの上限2 ^ 31または2 GBです。(MAX_ARG_STRLEN
カーネルソース。)
オペレーティングシステムの引数渡し制限は、シェルインタープリター内で発生する展開には適用されません。したがって、xargs
またはの使用に加えてfind
、シェルループを使用して処理を個々のmv
コマンドに分割することができます。
for x in *; do case "$x" in *.jpg|*.png|*.bmp) ;; *) mv -- "$x" target ;; esac ; done
これはPOSIXシェルコマンド言語の機能とユーティリティのみを使用します。この1行はインデントでより明確になり、不要なセミコロンが削除されています。
for x in *; do
case "$x" in
*.jpg|*.png|*.bmp)
;; # nothing
*) # catch-all case
mv -- "$x" target
;;
esac
done
mv
を使用すると、find
@ Gillesが投稿したPOSIX ソリューションを使用して必要な数個のプロセスではなく、100万を超えるプロセスが生成されます。つまり、この方法では不必要なCPUチャーンが大量に発生します。
case
ための*
拡張の結果に関するステートメントは、元の!(*.jpg|*.png|*.bmp)
式と同等であることが簡単にわかります。find
答えは等価ではないという事実にあります。サブディレクトリに降ります(-maxdepth
述語が表示されません)。
-name . -o -type d -prune -o
サブディレクトリへの下降から保護します。-maxdepth
明らかにPOSIX準拠ではありませんが、私のfind
manページには記載されていません。
以前に提供されていたものよりも積極的なソリューションについては、カーネルソースをプルアップして編集してください include/linux/binfmts.h
のサイズをMAX_ARG_PAGES
32より大きい値に増やします。これにより、カーネルがプログラム引数に許可するメモリ量が増加し、それにより、100万個のファイルまたは実行しているものにコマンドmv
またはrm
コマンドを指定できます。再コンパイル、インストール、再起動します。
気をつけて!これをシステムメモリに対して大きすぎる値に設定してから、多くの引数を指定してコマンドを実行すると、悪いことが起こります!これをマルチユーザーシステムに対して非常に慎重に行うと、悪意のあるユーザーがすべてのメモリを使い果たすのが容易になります。
カーネルを手動で再コンパイルして再インストールする方法がわからない場合は、現時点ではこの答えが存在しないふりをするのが最善です。
"$origin"/!(*.jpg|*.png|*.bmp)
catchブロックの代わりに使用するより単純なソリューション:
for file in "$origin"/!(*.jpg|*.png|*.bmp); do mv -- "$file" "$destination" ; done
@Score_Underに感謝
複数行のスクリプトの場合、次のことができます(ドロップさ;
れる前に注意してくださいdone
):
for file in "$origin"/!(*.jpg|*.png|*.bmp); do # don't copy types *.jpg|*.png|*.bmp
mv -- "$file" "$destination"
done
すべてのファイルを移動するより一般化されたソリューションを実行するには、ワンライナーを実行できます。
for file in "$origin"/*; do mv -- "$file" "$destination" ; done
インデントを行うと、次のようになります。
for file in "$origin"/*; do
mv -- "$file" "$destination"
done
これにより、元のすべてのファイルが取得され、それらが1つずつ宛先に移動されます。$file
ファイル名にスペースまたはその他の特殊文字が含まれている場合は、引用符で囲む必要があります。
完全に機能するこのメソッドの例を次に示します
for file in "/Users/william/Pictures/export_folder_111210/"*.jpg; do
mv -- "$file" "/Users/william/Desktop/southland/landingphotos/";
done
!(*.jpg|*.png|*.bmp)
。それをグロブ"$origin"/!(*.jpg|*.png|*.bmp)
することでforループに追加できます。これにより、Kazの答えで使用されるスイッチが不要になり、forループの単純なボディを維持できます。
これが私の2セントです。これを .bash_profile
mv() {
if [[ -d $1 ]]; then #directory mv
/bin/mv $1 $2
elif [[ -f $1 ]]; then #file mv
/bin/mv $1 $2
else
for f in $1
do
source_path=$f
#echo $source_path
source_file=${source_path##*/}
#echo $source_file
destination_path=${2%/} #get rid of trailing forward slash
echo "Moving $f to $destination_path/$source_file"
/bin/mv $f $destination_path/$source_file
done
fi
}
export -f mv
使用法
mv '*.jpg' ./destination/
mv '/path/*' ./destination/