たとえば、数百または数千のファイルを含むフォルダーがあり、それらはすべて次のスキーマに従って名前が付けられているとします。
<random number of variable length>_<date code in YYYYMMDD format>.jpg
例:
73923_20180927.jpg
4457582_20180927.jpg
...
18733557_20190401.jpg
23573_20190401.jpg
...
私のbashスクリプトが行うことを期待しているのは、それらの日付コードのリストを出力することです。
20180927
20190401
...
それは実際よりも簡単な作業のように思えます。スキーマは常に同じなので、ファイル名の必要な部分のみを印刷するために文字列操作を適用することはすでに達成しています。ただし、各日付を 1 回だけ印刷する方法をまだ考えています。
この状況から抜け出す良い方法はあるでしょうか?
答え1
ファイル名がすべてパターンに一致すると仮定します./*_*.jpg
:
for name in ./*_*.jpg; do
name=${name##*_} # 4457582_20180927.jpg --> 20180927.jpg
printf '%s\n' "${name%.jpg}" # 20180927.jpg --> 20180927
done | sort -u
これはすべての名前を反復処理します。名前ごとに、 に一致する最長のプレフィックス文字列を削除します*_
。次に、.jpg
サフィックスを削除した残りの文字列を出力します。
すべての文字列は、最後に一意の文字列のリストのみが出力されるようにソートされます。
ディレクトリが空になるリスクがある場合は、nullglob
ループの前にシェル オプション ( shopt -s nullglob
) を設定する必要があります。これにより、 内の展開されていないグロブ パターンを使用してループが 1 回実行されるのではなく、ループがまったく実行されなくなります$name
。
特に理由はありませんが、以下はなしで実行する方法になりますsort
:
declare -A skip=()
for name in ./*_*.jpg; do
key=${name##*_} # 4457582_20180927.jpg --> 20180927.jpg
key=${key%.jpg} # 20180927.jpg --> 20180927
if [[ ! -v skip[$key] ]]; then
printf '%s\n' "$key"
skip[$key]=1
fi
done
ここでは、連想配列のキーとしてすでに出力されている文字列を追跡します。skip
配列内のキーに対応する文字列は出力されません。
答え2
実際に不適切なファイル名がないと仮定して、そのディレクトリで実行します。
ls -U | awk '-F[_.]' '{ print $2 }' | sort | uniq