次のように、ファイル名にYYYYMMDD
という名前のファイルがあります。
file-name-20151002.txt
thisファイルが2015-10-02以降に変更されたかどうかを確認したい。
ls
の出力を確認することでこれを行うことができますが、ls
の出力を解析することは悪い考えであることはわかっています。20151002
の名前は2015年10月3日以降に変更されました。ここではいくつかの可能な方法があります:
OSX stat
:
newer () {
tstamp=${1:${#1}-12:8}
mtime=$(stat -f "%Sm" -t "%Y%m%d" "$1")
[[ ${mtime} -le ${tstamp} ]] && printf '%s\n' "$1 : NO: mtime is ${mtime}" || printf '%s\n' "$1 : YES: mtime is ${mtime}"
}
GNU date
:
newer () {
tstamp=${1:${#1}-12:8}
mtime=$(date '+%Y%m%d' -r "$1")
[[ ${mtime} -le ${tstamp} ]] && printf '%s\n' "$1 : NO: mtime is ${mtime}" || printf '%s\n' "$1 : YES: mtime is ${mtime}"
}
zsh
のみ:
zmodload zsh/stat
newer () {
tstamp=${1:${#1}-12:8}
mtime=$(zstat -F '%Y%m%d' +mtime -- $1)
[[ ${mtime} -le ${tstamp} ]] && printf '%s\n' "$1 : NO: mtime is ${mtime}" || printf '%s\n' "$1 : YES: mtime is ${mtime}"
}
使用法:
新しい ファイル
出力例:
file-name-20150909.txt : YES: mtime is 20151026
または
file-name-20151126.txt : NO: mtime is 20151026
次のスクリプトは、コマンドラインで指定されたすべてのファイルの日付をチェックします。
GNU sed
、date
、およびstat
のバージョンが必要です
$ cat check-dates.sh
#! /bin/bash
for f in "$@" ; do
# get date portion of filename
fdate=$(basename "$f" .txt | sed -re 's/^.*(2015)/\1/')
# convert it to seconds since Epoch + 1 day
fsecs=$(echo $(date +%s -d "$fdate") + 86400 | bc )
# get modified timestamp of file in secs since Epoch
ftimestamp=$(stat -c %Y "$f")
[ "$ftimestamp" -gt "$fsecs" ] && echo "$f has been modified after $fdate"
done
$ ./check-dates.sh file-name-20151002.txt
file-name-20151002.txt has been modified after 20151002
$ ls -l file-name-20151002.txt
-rw-rw-r-- 1 cas cas 0 Oct 26 19:21 file-name-20151002.txt
これはテストされていないバージョンですが、オンラインのmanページを正しく読んだ場合、Mac(およびFreeBSDなど)で動作するはずです。
#! /bin/bash
for f in "$@" ; do
# get date portion of filename
fdate=$(basename "$f" .txt | sed -e 's/^.*\(2015\)/\1/')
# convert it to seconds since Epoch + 1 day
fsecs=$(echo $(date -j -f %Y%m%d "$fdate" +%s) + 86400 | bc )
# get modified timestamp of file in secs since Epoch
ftimestamp=$(stat -f %m "$f")
[ "$ftimestamp" -gt "$fsecs" ] && echo "$f has been modified after $fdate"
done
あなたはこれを行うことができます:
touch
コマンド(時間/分/秒に0を追加)を使用して一時ファイルの変更日を設定しますあなたの質問はbash
に関するものなので、おそらくLinuxを使用しています。 Linuxで使用される test
プログラム( coreutils の一部)には、タイムスタンプ比較用の拡張機能(-nt
および-ot
)が見つかりません POSIX test
。
POSIXはこれについてtest
の根拠でコメントしています:
新しく発明された、またはKornShellから追加されたいくつかの追加のプライマリは、条件付きコマンド(
[[]]
)の一部として初期の提案に登場しました:s1> s2、s1 <s2、str =パターン、str! f1 -ot f2、およびf1 -ef f2。これらは、shユーティリティの歴史的な実装に組み込まれているテストユーティリティに含まれていないため、条件付きコマンドがシェルから削除されたときに、テストユーティリティに持ち越されませんでした。
その拡張機能を使用すると、次のことができます
test
の-nt
演算子を使用して、要求した比較を行います。例を示します。 OPによる説明でプラットフォームについて言及したため、一時ファイルの代わりにstat
を使用できます(比較 [〜#〜] osx [〜#〜] および Linux ):
#!/bin/bash
# inspect each file...
with_tempfile() {
echo "** with temporary file $name"
test=$MYTEMP/$name
touch -t $date $test
[ $name -nt $test ] && echo "...newer"
}
# alternatively (and this is system-dependent)
with_stat() {
echo "** with stat command $name"
stat=$(stat -t "%Y%m%d%H%M" -f "%Sm" $name)
[ $stat -gt $date ] && echo "...newer"
}
MYTEMP=$(mktemp -d /var/tmp/isnewer.XXXXXX)
trap "rm -rf $MYTEMP" EXIT
for name in file-name-[0-9][0-9]*.txt
do
if [ -f "$name" ];
then
date=${name%%.txt}
date=${date/file-name-}
date=${date//-/}2359
with_tempfile $name
with_stat $name
fi
done
Bashとstat
とexpr
を使用して日付を数値として取得し、それらを比較します。
#!/bin/bash
for file
do moddate=$(stat -f %m -t %F "$file") # MacOS stat
moddate=${moddate//-/} # 20151026
if filedate=$(expr "$file" : '.*-\([0-9]*\).txt')
then if [ $moddate -gt $filedate ]
then echo "$file: modified $moddate"
fi
fi
done
これは私の以前のLinux固有の答えでした。
#!/bin/bash
for file
do moddate=$(stat -c %y "$file")
moddate=${moddate%% *} # 2015-10-26
moddate=${moddate//-/} # 20151026
if [[ "$file" =~ ([0-9]{8}).txt$ ]]
then if [[ $moddate > ${BASH_REMATCH[1]} ]]
then echo "$file: modified $moddate"
fi
fi
done
Bash =~
regexp演算子は、ファイル名の8桁をbash配列BASH_REMATCHにキャプチャします。 [[ ]]
では文字列を比較しますが、[ -gt ]
では文字列を数値として比較するだけです。
別のzsh
アプローチ:
_zmodload zsh/stat # best in ~/.zshrc or
zmodload -F zsh/stat +b:zstat # to avoid overriding an eventual
# system stat command.
setopt extendedglob # best in ~/.zshrc
ls -ld -- **/*[0-9](#c8)*(De@'zstat -F %Y%m%d -A m +mtime $REPLY &&
[[ ${(SM)${REPLY:t}#[0-9](#c8)} != $m ]]'@)
_
名前にタイムスタンプのように見えるものの、最後の変更時刻に対応しないファイルを報告します。
zsh
には、グロブや変数を操作するための演算子がたくさんあります。すべての仕事をすばやく(そして一般的には確実に)実行するのは非常に便利ですが、それらすべてを理解するのは非常に難しく、通常はwrite-onlyコードと呼ばれるコードを生成します(判読不能なコードの冒涜、ただし、コマンドプロンプトで1回使用するために書き込むときに読み取る必要がないことも意味します)
簡単な概要:
**/pattern(qualifier)
:glob修飾子付きの再帰glob。[0-9](#c8)
は8桁に一致します。これは、ksh
の{8}([0-9])
に相当するzsh extendedglobです。D
:隠しファイルを含めるe@...@
_:evalglob修飾子。テキストを実行してファイルをさらに修飾します。 _$REPLY
_で渡されるファイルパスzstat...
_ _$m
_配列でYYYYMMDDとしてフォーマットされたmtimeを取得します。${REPLY:t}
_:ファイルのt tail(ベース名)に展開されます。${(SM)something#pattern}
。 somethingからpatternに一致する部分を抽出します。これらのS
([〜#〜] s [〜#〜] ubstring search)およびM
(expand to [〜#〜] m [ 〜#〜]キャッチされた部分)が呼び出されますパラメーター展開フラグ。