
設定された制限を超えた場合に古いファイルを消去するスクリプトがあります。
このコマンドがあります:
/bin/rm -f `/bin/ls -t $bkup_p/mysql.daily/* 2> /dev/null | /bin/awk 'NR>'5`
これは動作しますが、$bkup_pにスペースがある可能性があるため、次のように変更してみました。
/bin/rm -f `/bin/ls -t "$bkup_p/mysql.daily/*" 2> /dev/null | /bin/awk 'NR>'5`
しかし、それは機能しません。問題のファイルは表示されず、空のままです。
答え1
Bash は、変更時間に基づいてファイルをフィルタリングし、そのファイルに対してコマンドを実行する場合にはあまり便利ではありません。
代わりにz-shellを試すことをお勧めします。まずは を実行しzsh
、次に
rm -i -- "$bkup_p"/mysql.daily/*(DN.Om[1,5])
これにより、指定されたディレクトリ内の最も古い 5 つのプレーン ファイルが削除されます。おそらくこれが、あなたが達成しようとしていることだと思います。明らかに、最終的には必要rm -i
に応じて変更しますrm -f
。
最新の5つのファイルを削除するには
rm -i -- "$bkup_p"/mysql.daily/*(DN.om[1,5])
さて、これがどのように動作するかです。内部にあるものはすべて、()
いわゆる glob 修飾子で、基本的にはニーズに応じてファイルをフィルタリングします。
D
ドットファイル( で始まるもの.
)を含めるN
一致しない場合はエラーを報告しない.
プレーンファイルのみを選択しますom
更新時刻でソートします(Om
逆順にソートします)[1,5]
リストから5つのファイルのみを選択します
ファイル名に特殊文字 (スペース、改行など) が含まれていても、これらすべてが機能するはずです。
答え2
他の人が言っているように、ls
そのためには使用すべきではありません。しかし、あなたの環境にもっと適切なものがなく、注意点を知る、 あなたかもしれないファイル名が十分いい: 空白文字や印刷できない文字は使用不可です。特に、シェルがグロブ文字として解釈するもの (少なくとも?*[]
) は使用できません。
Perl などを使用してファイルを並べ替えるか、ファイル名に日付を入れて glob 順序に依存できるようにする方がよいでしょう。
そうは言っても、2 番目のスニペットではアスタリスクが引用符で囲まれているため、グロブは発生しません。存在しないというエラーが表示されますsome dir/mysql.daily/*
が、エラー出力をリダイレクトしているため、表示されません。
スペースを含むファイル名を使用すると、コマンド置換からの出力がスペースで分割されるという問題が発生します。そのため、 のようなものはとの 2 つの部分に分割some dir/foo
されます。どちらも存在しないことを願います。削除されてしまうからです。rm
some
dir/foo
ディレクトリ名にのみスペースが含まれている場合は、cd
最初にそのディレクトリ名を入力するだけで済みます。または、IFS
改行のみが含まれるように設定します (デフォルトのスペース、タブ、改行の代わりに)。NAS について言及されているので、busybox をお持ちである可能性があります。これは、busybox と bash の両方で機能し、ファイル名を 1 行に 1 つずつ出力します。
IFS=$'\n'
printf "%s\n" $( ls -t "$bkup_p/mysql.daily/"* | tail -n +6 )
正しく動作することを確認したら、printf "%s\n"
を に置き換えてファイルを削除します。rm
答え3
の出力を解析することはお勧めしません。ls
新しいコマンドにパイプするための出力を適切にフォーマットせず、移植性の問題があるためです。
代わりに次のようなことを試してください。
find $bkup_p/mysql.daily/ -type f -a -mtime +7 -a -name "*.sql" -a -exec rm -f {} +
注記:
"*.sql"
必要に応じて変更してください-mtime +7
*このファイルが7日以上前に変更された場合は、必要に応じてこれも変更してください
常に最新の10個のファイルがあることを確認したい場合は、(GNUを使用している場合はfind
)次のようにします。
find $bkup_p/mysql.daily/ -maxdepth 1 -type f -a -printf "%T+\t%p\n" | sort -r | sed -n '10,$p' | awk '{print $2}' | xargs rm -f
find
演算子による出力のフォーマットの詳細については-printf
、
man find | less '+/^\s*-printf'
答え4
動作しない問題は*
、引用したときに展開されないためです。
次の結果を次の結果echo *
と比較してくださいecho "*"
。
堅牢な解決策は、配列の各位置に 1 つのファイルを配置して配列を使用することです。
運が良ければ、次のサポートを見つけることができます-printf
:
dir="$bkup_p/mysql.daily/"
find "$dir" -printf '%T@:%i\n'
すべてのファイル名は避けられます。各ファイルは 1 行になります。また、数字、オプションのドット、コロンのみからなる行になります。
それは簡単に分類できます:
find "$dir" -printf '%T@:%i\n' | sort -rn
最も単純な配列は位置引数です。
これにより、ディレクトリ内のすべてのファイルが位置引数のリストに設定されます。
set -f; set -- $(find "$dir" -printf '%T@:%i\n' | sort -n )
set -f は、ワイルドカードでもあるファイル名の展開を回避します*
。最初の 6 つのファイル名を回避 (削除) するには、shift
次の操作を実行します。
shift 5
残りのファイルに対して必要な操作を行います。
for f
do rm -f "$(find "$dir" -inum "${f#*:}")"
done
脚本全体。
スクリプト全体(どのファイル名に対しても堅牢)は次のようになります。
dir="$bkup_p/mysql.daily/"
set -f
set -- $(find "$dir" -type f -printf '%T@:%i\n'|sort -rn)
shift 5
for f
do rm -f "$(find "$dir" -inum "${f#*:}")"
done