配列に保存されている複数のディレクトリを消去しようとしています。以下は簡単な例です(より多くのディレクトリがあります)。
#!/bin/bash
$IMAGES_DIR="/Users/michael/scripts/imagefiles"
$BACKUP_DIR="/Users/michael/scripts/imagebackups"
...
array=( $IMAGES_DIR $BACKUP_DIR )
for i in ${array[@]}
do
if [ "$(ls -A $i)" ]; then # check that directory has files in it
rm "$i/"* # remove them
fi
done
各ディレクトリに対して、次のエラーが発生します。
rm: /Users/michael/scripts/imagefiles/*: そのファイルやディレクトリはありません。
答え1
1つのコマンドですべてを行うのはどうですか?
単一の呼び出しでファイルの存在確認、グロービング、削除をキャプチャできますfind
。 GNUバージョンの場合、find
次のものがあります。
for f in "${array[@]}"; do
find "$f" -type f -delete
done
GNU がない場合は、find
次の呼び出しを使用します。
find "$f" -type f -exec rm -f {} +
(ディレクトリ階層全体でファイルを消去せずに直接サブファイルのみを消去する場合は、-maxdepth 1
前に追加してください-type f
。)
しかし、待って、もっとあります…
〜のようにJohn1024は賢明に指摘しています。配列を最初の引数として渡すことで、ループを完全に中断できますfind
。
find "${array[@]}" -type f -delete
その理由は次のとおりです。1) find
1回の実行で複数のディレクトリを検索して処理できます。2)シェルは、各要素(ディレクトリ)が別々の位置引数になるように配列を分割しますfind
。
答え2
コードを次のように変更してください。
#!/bin/bash
IMAGES_DIR="/Users/michael/scripts/imagefiles"
BACKUP_DIR="/Users/michael/scripts/imagebackups"
array=( $IMAGES_DIR $BACKUP_DIR )
for i in "${array[@]}"
do
if [ "$(ls -A "$i")" ]; then
rm "${i:?}"/*
fi
done
間違い:
$
変数の割り当ての左側に配置$i
引用しないif [ "$(ls -A $i)" ];then
"${var:?}"
これを保証するために使用され、決してrm "$i/"*
拡張されません。/*
答え3
オプションを使用すると、ファイルオペランドが存在しない場合、ユーティリティは文句を言いません-f
。rm
また、失敗すると終了しません。
何ですか可能あなたの場合、隠された名前のファイルまたはディレクトリを除いて1つ以上のディレクトリが空であるため、パターンの末尾*
にあるディレクトリは何も拡張されません。シェルオプションを設定して、*
globが隠された名前と一致するようにすることができます。bash
dotglob
また、割り当てに変数名を使用しないでください。$
トークン化やファイル名の生成(ワイルドカード)を防ぐために、二重引用符変数の拡張が必要です。誤って環境変数や特殊シェル変数を破壊しないように、変数名は小文字でなければなりません。
これらの要素を考慮した代替コードの定式化。
#!/bin/bash
shopt -s dotglob
images_dir="/Users/michael/scripts/imagefiles"
backup_dir="/Users/michael/scripts/imagebackups"
dirs=( "$images_dir" "$backup_dir" )
for dir in "${dirs[@]}"; do
rm -f "$dir"/*
done
上記のコードは、ディレクトリからすべてのファイルを削除しようとします。ディレクトリにサブディレクトリがあると、rm
それに関連するエラーが発生します。これらも削除するには、-r
withを使用しますrm
。
答え4
rm
目標がフォルダ配列内のすべてのファイルを削除することである場合、別のオプションは次のように配列を渡すことです。
#!/bin/bash
$IMAGES_DIR="/Users/michael/scripts/imagefiles"
$BACKUP_DIR="/Users/michael/scripts/imagebackups"
# ...
# to preserve whitespaces in path strings, add double quotes around each variable
array=( "$IMAGES_DIR" "$BACKUP_DIR" )
# this appends "/*" to the end of each dirname if you want to delete the contents of the directories
# without deleting the directories themselves
array=( "${array[@]/%//*}" )
# this will spread the array into multiple calls to rm
rm -rf ${array[@]}
一行の例:
rm -rf ${array[@]/%//*}
ただし、フォルダも削除するには、次のものを使用できます。
rm -rf ${array[@]}
注目すべき違いB層溶液、whileはfind
指定されたパスを探している間に発生するすべてのエラーを印刷しますrm
が、この場合はそうではありません。
編集する:
〜のように先行パスにスペースやシェルワイルドカードがある場合は、このように配列を拡張することが危険になる可能性があることに注意することが重要です。これらの文字によって配列が分割されるのを防ぐには、配列に追加する変数の周りに二重引用符を追加する必要があります。