tuneoの日記: シェル力を高める:こんなパイセンにつける薬はありませんか 18
日記 by
tuneo
だってパイセンときたら勤続10年のベテランなのに「とあるディレクトリ以下を再帰的に検索し、ファイルの最終更新日が30日以前であれば削除する」スクリプトを書くのに1時間かけてるんです。なんつー時間の無駄。
しかも自分でman findしてひねり出したから1時間かかりました、とかじゃなくてGoogle先生にお伺いを立ててヒットしたブログの丸写し。その結果、検索条件が見事に「作成日が30日以前」になってやがったし、ディレクトリも削除しようとしてたし、ファイル名に空白が入っていたらどうなるかの考慮はゼロ。あと俺がman findしながら書き散らしていたら、ド厚かましいことに「削除するファイルのログが取れるといい」とか言い出しやがりました。自分じゃできないくせに他人に要求するのはいっちょ前なんだよなぁ。
というわけで帰宅前に15分(実際にはテストに時間を食われていたんだけど)でひねくりだしたのがこんなの。
#!/bin/sh
DIR=/directory
LOG=logfile
find "$DIR" -type f -daystart -mtime +30 -print0 | tee "$LOG" | xargs -0 rm -f
……そんなクソ仕事でも得られるものはゼロじゃない。別に得たくはなかったが。
・テスト用のダミーファイルをでっち上げるときtouch -t MMDDhhmm fileとか書くとタイムスタンプ(最終更新日)を指定して空のファイルを作成することができる。便利。
・ディレクトリのタイムスタンプもtouch -tでいじれる。ただしこの場合はtouchでディレクトリを作るわけにはいかないので事前にmkdirが必要。
logfile (スコア:2)
tee に -a オプション付けないと上書されるよ
タイムスタンプも入ってないといつのログか分からないので、むしろファイル名を以下のようにして、実行毎に別ファイルにするべきじゃないかと思う。
LOG=logfile.`date +%Y%m%d%H%M%S`
uxi
自分がやるとすると (スコア:2)
find の -exec オプション使って以下のようにするかな?
find "$DIR" -type f -daystart -mtime +30 -exec rm -fv {} + > "$LOG"
uxi
Re:logfile (スコア:1)
その辺は tee よりも実行権限を要求されても logger の方が後腐れないかな。
それはそれでログファイルを汚すななどという原理主義者と戦うことになったり
等システムレイヤのの8層/9層とも調整しないといけないから大仕事だけど。
Re:logfile (スコア:1)
脱線するけど、
ログファイル名に何と情報を示せ(混同誤用を避けるため)とかメタデータ作れとか
一段ディレクトリを掘って隔離しろなどと心無い指摘の懸念ありやなしや?
Re:logfile (スコア:1)
その辺は気にしなくていいのです。直近の実行結果だけ記録するんだそうで。
find $DIR -mtime +30 -print -exec rm '{}' \; (スコア:1)
タイトルはスクリプトキディ気取りで。
プレーンファイルのみとかログとかはばっさり無視する前提で。
ええと、 xargs でファイル名に空白文字を含んだをパイプで引き渡すと
意図しない挙動になる
具体的には
1. 誤った解釈でブランク・キャラ直前でぶった切られた名前で処理。
2. その際に本来ありえなかった標準エラー出力がべろべろ吐き出される。
は避けるべきではないかと。
(エラー出力が処理と同期して得られる保証がないので見て切り分けがつらいはず)
Re:find $DIR -mtime +30 -print -exec rm '{}' \; (スコア:1)
寝て起きたら気づきましたが、find -print0でNUL区切りでファイル名出してxargs -0 rmで削除してる狭間にteeはさんだらダメですねぇ。
ということでrm -fvをリダイレクトするべきでしたw
Re:find $DIR -mtime +30 -print -exec rm '{}' \; (スコア:1)
-exec rm は、ファイル一個一個ずつrmコマンドを呼び出すので、xargs の方が望ましいでしょう。
で、xargsで空白文字入りのファイル名がいけるようにするのが、find の -0 オプションと、xargs の -0 オプション。
findは空白ではなく、\0 区切りで出力し、xargs は \0 区切りで読み込み分割処理します。
#すでに自己ツッコミが入ってますが、\0区切りなのでteeしたらダメですね。
それにしても、find を今回のネタのように使うときは、毎回「 -mtime の + と - って、どっちが新しいほうだっけ?」って悩んでしまいます。man を見ても微妙な感じなで自身が持てないので、毎回まずprintだけして確認してる…
あとは、適当にtouchしたファイルを元に-newer したりとか。これは字面から勘違いしようがないし。
Re:find $DIR -mtime +30 -print -exec rm '{}' \; (スコア:2)
最近は-exec xxx {} \;じゃなくて-exec xxx {} +だなぁ。;をエスケープしなくていいし。
えPOSIXじゃないのはだめ?
Re:find $DIR -mtime +30 -print -exec rm '{}' \; (スコア:1)
最新標準、筋の良さなど多数派として正当とアピールできる観点を無視すれば
わたしが頑迷な守旧派として悪目立ちできている、ということでいいですね?!
やっぽー!
Re:find $DIR -mtime +30 -print -exec rm '{}' \; (スコア:1)
findにもxargsにも空白文字入りファイル対策があったとは。
ご教示多謝。不明を恥じます。
正直なところ find コマンドをふりかざす時点でリソースを
がっつり大食いする前提なのであれこれと見積もりが甘くなるきらいあり。
Re:find $DIR -mtime +30 -print -exec rm '{}' \; (スコア:1)
ログを取るタイミングとしては他に、xargsを実行するときと、rmを実行するときがあって、それぞれ以下の通り:
xargs -t
rm -v
後者はお気づきの通り。
ファイル名については、空白が含まれることの他に、可能性は低くてもあり得るのは、ハイフン「-」で始まること。例えば、
rm -AFileStartingWithHypen
が失敗してしまう。
これを防ぐには
rm -- -AFileStartingWithHypen
とする、ってことらしいです。
Re:find $DIR -mtime +30 -print -exec rm '{}' \; (スコア:1)
2点ご指摘多謝。
とりわけハイフンを含むファイル名の事故ケースは指示通り実行して
いったん抹消したら影響が軽微でも原状回復が面倒なケースに直結する予感。
Re:find $DIR -mtime +30 -print -exec rm '{}' \; (スコア:1)
しかしながら POSIX 非標準なので、某原理主義とかでは使うことが出来ず困ってしまうかも。
実際のところこれらが無い環境って存在するのだろうか。
Re:find $DIR -mtime +30 -print -exec rm '{}' \; (スコア:1)
>某原理主義
Version 7 にあこがれているわたしは Version 8 もなんだかなー
というくらいの原理主義者かもしれない。
// コメントにカナ漢字を使うのにもどうやるの?と悩んだ発端の契機から。
ファイル名に空白が入っていたらどうなるか (スコア:1)
内々ではそんなファイルは作らない前提で仕事してたけど。
SAMBAとかでWindowsから日本語ファイル名や空白入りファイル名をジャカスカほうり込んでくる人たちが現れて、文字化けでファイルハンドリングできなくて異動も削除もできないとかで阿鼻叫喚になったこともあったっけ。
find の -print0 と xargs の -0 は知らなかった・・・
うちでやってる仕事例(粗野)
% find /hoge/fuga/ -type f -mtime +30 > list0; cat list0 | xargs -i{} \rm -f {} \;
Re:ファイル名に空白が入っていたらどうなるか (スコア:1)
ひとつのプロセス起動するときに限界まで引数を詰め込んでくれるし、その気になれば並列化もできるのでxargsは積極的に使ってます。
ちなみに私はxargsを先に覚えた結果、いまの会社に就職するまでforとかwhileでループを回すシェルスクリプトを書けませんでしたが(自作スクリプトはPythonで書いてたし)、パイセンがあまりにポンコツなので必要に迫られて覚えました(苦笑
Re:ファイル名に空白が入っていたらどうなるか (スコア:1)
xargs 何かと便利ですね。
awkその他と合わせたら色々できるので重宝してます。
♯知らないことのほうが多いけど