「foo.date.bar」という形式の名前の一連のファイルがあります。「date」は310715などの6桁のフィールドです。
だから例えば
foo.310715.bar
foo.260815.bar
foo.110815.bar
foo.040815.bar
スクリプトがそれらの一部を削除できるように、ファイルのメタデータではなくファイル名の日付に基づいて、これらを日付順に並べ替えたいと思います。通常、これはPythonまたはPHPで簡単に実行できますが、Bashで処理する方法を学習しようとしています。コマンドでの最初の試行
for f in $( find $dir -type f | sort -r -t. -k 2 ); do
echo $f
done
しかし、2番目の列を数値またはアルファベット順に並べ替えても意味がないことに気付きました。日付として並べ替える必要があります。 sort
に、6桁のフィールドを日付として扱う方法、または3つの2桁の列として扱う方法を伝える方法はないようです。次のステップは、sed
やtr
などを使用して、6桁のフィールドをsort
が解析できるものに変換することでしょうか。
助けてくれてありがとう、
MB
皆さんの素晴らしい答えに感謝し、私はそれらを読むことから多くを学びました。
これがbash配列の乱用です。タイムスタンプを分割し、YYMMDDの順序に基づいて配列エントリを作成してから、配列を順番に出力します。
declare -a array
for file in foo.*.bar
do
[[ $file =~ foo.([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2}).bar ]] && \
{
index="${BASH_REMATCH[3]}${BASH_REMATCH[2]}${BASH_REMATCH[1]}"
array[$index]="$file"
}
done
for index in "${array[@]}"
do
echo $index
done
# or
printf "%s\n" ${array[@]}
次のパイプシーケンスでは、sed
を使用して、最初に*.DDMMYY.*
形式のファイル名を*|DD|MM|YY|*
形式に変更します。再フォーマットされた出力はsort
にパイプされます。ここで '|'はフィールド区切り文字として使用され、最初にYY(-k4n
)、次にMM(-k3n
)、最後にDD(-k2n
)でソートされます。次に、ソートされた出力がパイプでsed
に戻され、ファイル名が元の形式*.DDMMYY.*
に変換されます。
sed 's/\.\([[:digit:]]\{2\}\)\([[:digit:]]\{2\}\)\([[:digit:]]\{2\}\)\./|\1|\2|\3|/' | \
sort -t'|' -k4n -k3n -k2n | \
sed 's/|\([[:digit:]]\{2\}\)|\([[:digit:]]\{2\}\)|\([[:digit:]]\{2\}\)|/.\1\2\3./'
次のファイルのサンプルを使用します。
$ ls *bar -1
abc.291015.bar
abc.291115.bar
abc.291215.bar
abc.301215.bar
foo.040815.bar
foo.150115.bar
foo.150914.bar
foo.260815.bar
foo.301216.bar
foo.310715.bar
xyz.010113.bar
シーケンスは次を生成します:
xyz.010113.bar
foo.150914.bar
foo.150115.bar
foo.310715.bar
foo.040815.bar
foo.260815.bar
abc.291015.bar
abc.291115.bar
abc.291215.bar
abc.301215.bar
foo.301216.bar
GNUまたはFreeBSDsort
がある場合は、最初にsed
を使用してスワップした後、-V
または--version-sort
オプションを使用できます。日付形式(そして、日付形式を元に戻すには、もう一度sed
):
ls -1 |
sed -E -e 's/^(.*\.)(..)(..)(..)(.*)$/\1\4\3\2\5/' |
sort -V |
sed -E -e 's/^(.*\.)(..)(..)(..)(.*)$/\1\4\3\2\5/'
理想的には、ファイルの名前を変更して、便利な日付形式にする必要があります。例えばPerl名前変更ユーティリティの使用prename
:
$ prename -v 's/^(.*\.)(..)(..)(..)(.*)$/$1$4$3$2$5/' *
foo.040815.bar renamed as foo.150804.bar
foo.110815.bar renamed as foo.150811.bar
foo.260815.bar renamed as foo.150826.bar
foo.310715.bar renamed as foo.150731.bar
$ ls -1 | sort -V
foo.150731.bar
foo.150804.bar
foo.150811.bar
foo.150826.bar
(ところで、ほとんどのprename
操作とは異なり、これはたまたまリバーシブルです。必要に応じて、もう一度実行して名前を元に戻すことができます)