web-dev-qa-db-ja.com

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

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

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を使用して希望のパターンを取得しますが、bash/zshでこれを行う方法がわかりません。

これはシェルスクリプト内でどのように実行できますか?

7
ylluminate

パラメータ展開 を使用する

$ 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}は、インデックス0から始まる4文字を意味し、fは変数名です
  • echo "$d"を自分のコードに置き換えます
9
Sundeep

現在のディレクトリ内のすべてのファイルをループして、それらのファイル名を目的のパターンと比較するには、日付の部分を含む変数を設定します

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's [[正規表現マッチングを使用する機能 日付部分をBASH_REMATCH配列に配置します。

5
Jeff Schaller

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
3
FloHe

これは、ループなしでこれを行うzsh方法です。

_autoload -U zmv
zmv -n '([0-9](#c4))-([0-9](#c2))-([0-9](#c2))(*)' '$1$2$3$4'
_
  • [0-9](#c4)は、4桁繰り返される数字を意味します
  • _$1_-_$2_以前に使用された括弧を参照
  • _-n_は実行を防止し(印刷のみ)、結果に満足したらこのフラグを削除します

zshはすべてのコーナーケース(空白、特殊文字など)をグロブ処理するので、自動的に考慮に入れられるべきです。

2
jimmij

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--date=STRINGオプションとまったく同じであるため、touchコマンドをスキップできます。

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

しかし、なぜtouchがGNU Coreutilsからのものである)に依存しているときに、この10文字がPOSIXポータブルな方法で切り刻まれるのでしょうか。

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

パターン置換を試してください:

${parameter/pattern/string}

パラメータはファイルのベース名です。パターンはダッシュです。この/-では、パターンをグローバルに置き換えます。ダッシュを削除するため、文字列は空です。

mv "${f}" "${f//-/}"

警告:拡張内のスペースの場合、これは機能しませんでした。

1
Martin Lange