目次
Unixで最新のファイルがあるディレクトリ一覧を作る
2015/02/15
解説入れておけよ、と高飛車に言われたので小心者の私は従いました。
2015/02/12
awkコマンド使用でつっこみあったので対応
2015/02/11
自分の理解の整理も兼ねてのメモ。備忘録。
「最新のファイル」の定義
ここで言う「最新のファイル」は、「1日前からスクリプト実行日時まで」のタイムスタンプを持つファイルを指すものとする。
以降の例では、findコマンドの -mtime オプションを適用し、コマンド実行日時を「最新の日時」と定め、この日時を元にファイルのタイムスタンプの条件を設定している。
例1:最新のタイムスタンプを持つファイルを一覧させる
find /home/user/work -type f -size -1000c -mtime -1 | sort
findコマンドでファイル一覧を出力。条件は以下。
- ディレクトリ /home/user/work 以降に配置されているファイルが対象。 -type f がその指定。
- 1000バイト以下のファイルが対象。-size -1000c がその指定。
- コマンド実行時刻から1日前までのタイムスタンプを持つファイルが対象。-mtime -1 がその指定。
見た目を揃えたいので sortコマンドでソートをかけた一覧に変更。なくてもいい。
例2:最新のタイムスタンプを持つファイルが存在するディレクトリを一覧させる
find /home/user/work -type f -size -1000c -mtime -1 | sed -E "s/\/[^\/]+$//" | uniq | sort
findコマンドでファイル一覧を出力。条件は以下。
- ディレクトリ /home/user/work 以降に配置されているファイルが対象。 -type f がその指定。
- 1000バイト以下のファイルが対象。-size -1000c がその指定。
- コマンド実行時刻から1日前までのタイムスタンプを持つファイルが対象。-mtime -1 がその指定。
sedコマンドでファイル一覧のファイルの部分を削除。
- -Eオプションで正規表現の解釈を拡張正規表現へ変更。+記号や$記号が意図したように効かなかった為。
- 正規表現の意味は「“/“で始まり”/“以外の文字で1文字以上行末まで続く部分」。
- sedのs関数で正規表現に一致した部分を“”に置き換え、つまり削除。結果、ディレクトリ部分のみ残る。
uniqコマンドでディレクトリ名の重複を消す。
- uniqコマンドで同一の内容を持つ複数行を1行にさせる。
- 同じディレクトリに同じタイムスタンプのファイルがあった場合、同じディレクトリの行が重複して残る。見た目が悪い。
uniqコマンドの出力で問題なければsortコマンドは使わなくてもいい。
別に最短一致させなくても大丈夫じゃないか、の指摘があったのでawkコマンドからsedコマンドに置き換えした。
追記:各ディレクトリで一番新しいファイル一覧が欲しいんじゃ
- newerlist.sh
for arg in `find /home/user/work -type d` do filename=`ls -F1tr "${arg}"/ | grep -v "/$" | tail -1` if test -n "${filename}" ; then echo "${arg}/${filename}" fi done
for文がfindコマンドの出力行数だけdo~doneの間の処理を繰り返す。10行出力されたなら10回ループ。変数$argに行の内容が入る。
findコマンドはディレクトリ /home/user/work 以降に配置されているサブディレクトリの一覧を出力。 -type d がその指定。
lsコマンドでfindコマンドの示すサブディレクトリ内の一覧を出力。タイムスタンプの昇順に出力される。
- -F:ディレクトリの名前の最後に”/“が付与される。
- -1:ファイル名、ディレクトリ名だけ表示。
- -t:タイムスタンプでソート。
- -r:ソートを降順から昇順に変える。
grepコマンドで最後が”/“の行をフィルタして出力しない。
- 正規表現の意味は「”/“が行末である」。
- -v は指定の正規表現に合致する行を出力しない。
- つまりlsコマンドの出力で行末が”/“の行はディレクトリだから処理対象にしない。
tailコマンドはheadコマンドの逆。-1 の指定で入力した一覧の最終行を出力。最終行はそのディレクトリ内で一番新しいファイルを指す。
if文の行はファイルが存在しないディレクトリだった時の為のもの。test -n は指定の文字列が長さゼロではないか否かの判定。長さゼロでなければ真。
ワンライナーにする方法が思いつかなかったので、シェルスクリプトでfindコマンドの出力結果でループしながらディレクトリ毎に確認しています。
一番新しいファイル(タイムスタンプが同じファイル)が二つ以上ある場合、どれが採用されるのかはファイル名によって決まるんじゃないかな。