findとmvの両方を使用する必要があります。
要件:すべての* .xmlファイルを見つける必要がありますが、預金.xmlを除いて別のフォルダに移動する必要があります(かなり簡単です)。
私の試み:
mv `find ./*.xml '!' -type d | fgrep -v deposit.xml` ./Archive
ファイルが存在する場合はうまく機能し、ファイルがない場合は次のエラーが発生します。
mv: missing destination file operand after `./Archive'
Try `mv --help' for more information.*
ベストアンサー1
ls
あるいは、出力を解析するのは一般的に、find
どの文字がファイル名の一部であるか区切り文字であるかを知ることができないため、悪い考えです。ファイル名を制御しないと、攻撃者がファイル名を偽造してスクリプトが任意のコードを実行できるようにするセキュリティの脆弱性になる可能性があります。バラよりスペースやその他の特殊文字が原因でシェルスクリプトが停止するのはなぜですか?。しかし、あなたの場合は大丈夫かもしれません。特に、ファイルが一種のソースコードツリーであるように見え、ファイル名に通常「エキゾチックな」文字がなく、特にスペースがない場合はそうです。
それでも強力なコマンドを使用することは実際には難しくありません。重要なアイデアは、構文解析の代わりにfind
呼び出しを実行することです。次のコマンドは、現在のディレクトリとサブディレクトリから再帰的に移動します。mv
find
.xml
find . ! -type d -name '*.xml' ! -name deposit.xml -exec mv {} ./Archive \;
作業速度を少し上げるには、mv
中間シェルを実行して呼び出しをペアにグループ化できます。
find . ! -type d -name '*.xml' ! -name deposit.xml -exec sh -c 'mv "$@" "$0"' ./Archive {} +
サブディレクトリを巡回せずに現在のディレクトリ内でのみファイルを移動するには、繰り返さないようにマークするfind
必要があります。find
実装がこのオプションをサポートしている場合-maxdepth
:
find . -maxdepth 1 ! -type d -name '*.xml' ! -name deposit.xml -exec sh -c 'mv "$@" "$0"' ./Archive {} +
それ以外の場合:
find . -name . -o -type d -prune -o -name '*.xml' ! -name deposit.xml -exec sh -c 'mv "$@" "$0"' ./Archive {} +
シェルがkshの場合は、拡張globを使用できます。これはを使用するよりも簡単ですが、find
移植性が低下します。現在のディレクトリからファイルを移動します。
mv !(deposit).xml Archive/
ksh93では、サブディレクトリからファイルを移動することもできます。
set -o globstar
mv **/!(deposit).xml Archive/
Bashでもこのモードを使用できますが、最初に実行する必要があり!(…)
ます。shopt -s extglob
このモードを使用するには**/
、まず実行する必要があります。bash 4.2までは、ディレクトリに加えてディレクトリへのシンボリックリンクも通過するshopt -s globstar
ことに注意してください。**/
shopt -s extglob globstar
mv **/!(deposit).xml Archive/
!(…)
zshではsetopt ksh_glob
。またはを実行した後、zshの構文を使用できますsetopt extended_glob
。どちらにしても、再帰巡回構文を使用できます。
setopt extglob
mv **/(^deposit).xml Archive/