ファイル名から特定の要素を抽出するには?

ファイル名から特定の要素を抽出するには?

次の形式のファイルがたくさんあります。

2014-11-19.8.ext
2014-11-26.1.ext
2014-11-26.2.blah.ext
2014-11-26_3.ext
2014-11-26.4.stuff_here.ext
2014-12-03.1. could be anything.ext
2014-12-032b.ext
2014-11-26 613 adva.ext

私の目標は、ファイルの全リストを繰り返して日付形式を取得し、それを処理するために変数にYYYY-MM-DD保存することです(私の場合はコマンドYYYYMMDDにプッシュされます)。touch

したがって、通常は次の正規表現と一致します。(\d{4})-(\d{2})-(\d{2}).*

次に、を使用して目的のパターンを取得しましたが、/でこれを行う$1$2$3方法がわかりません。bashzsh

シェルスクリプトでこれを行うにはどうすればよいですか?

答え1

使用パラメータ拡張

$ touch 2014-11-19.8.ext 2014-11-26.1.ext
$ for f in *.ext; do d="${f:0:4}${f:5:2}${f:8:2}"; echo "$d"; done
20141119
20141126
  • ${f:0:4}変数名であるindexから始めて4文字を表します0f
  • echo "$d"あなたのコードに置き換えてください。

答え2

現在のディレクトリ内の各ファイルを繰り返し、ファイル名を目的のパターンと比較するには、日付フラグメントを含む変数を設定します。

for f in *
do 
  [[ $f =~ ^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])(.*) ]] && 
  yourvar="${BASH_REMATCH[1]}${BASH_REMATCH[2]}${BASH_REMATCH[3]}"
done

これは以下を使用します。[[正規表現マッチングを使用するbash関数日付フラグメントを BASH_REMATCH 配列に入れます。

答え3

次のコマンドを使用して、対話的にこれを実行できますGNU sed

$ sed 's/^\([0-9]\{4\}\)-\([0-9]\{2\}\)-\([0-9]\{2\}.*\)/\1\2\3/g' stuff.txt

複数のファイルの場合(同じディレクトリにあり、そのディレクトリに考慮される他のファイルがない場合):

for file in *
do
    if [ -f "$file" ]
    then
          sed 's/^\([0-9]\{4\}\)-\([0-9]\{2\}\)-\([0-9]\{2\}\).*/\1\2\3/g' "$file"
    fi
done

答え4

GNU Coreutils を使用すると、以下が表示されます。

$ date --date=2014-11-13 +"%Y%m%d"
20141113

しかし:

$ date --date=2014-11-130ABCJUNK +"%Y%m%d"
date: invalid date ‘2014-11-130ABCJUNK’

したがって、作業ははるかに簡単です。YYYY-MM-DDetc各ファイル名の最初の10文字を抽出して日付自体を取得し、それをdate再フォーマットするために渡します。

ただし、GNU Coreutilsを使用している場合はまったく同じオプションがあるため、そのdateコマンドをスキップできます。touch--date=STRING

for file in * ; do
  date=${file%${file##??????????}} # chop all but first ten
  touch --date=$date -- "$file"
done

touchところで、GNU Coreutilsに依存するときにPOSIX移植可能な方法で10文字のスライスを実行するのはなぜですか?

for file in * ; do
  date=${file:0:10}
  touch --date=$date -- "$file"
done

関連情報