1. ホーム
  2. バッシュ

[解決済み】Grep RegExからグループをキャプチャする

2022-03-23 14:01:28

質問

私は、この小さなスクリプトを sh (Mac OSX 10.6) で、ファイルの配列に目を通すことができます。Googleはこの時点で役に立たなくなった。

files="*.jpg"
for f in $files
    do
        echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'
        name=$?
        echo $name
    done

ここまでは(シェルの達人の皆さんには当然ですが) $name は単に0、1または2を保持するだけです。 grep は、ファイル名が提供された事柄と一致することを発見した。 この括弧の中にあるものを取り込みたい。 ([a-z]+) に格納し、それを変数 .

私が望むのは を使用します。 grep のみ、可能であれば . そうでない場合は、PythonやPerlなどはご遠慮ください。 sed 私はシェルの初心者なので、*nixの純粋主義者の角度からこれを攻撃したいと思います。

また 超カッコイイボヌ シェルで文字列を連結する方法について教えてください。キャプチャしたグループが $name に格納されている "somename" という文字列で、その末尾に ".jpg" という文字列を追加したい場合、以下のようにすればよいでしょうか。 cat $name '.jpg' ?

お時間があれば、ご説明をお願いします。

解決方法は?

Bashを使用している場合は、特に何もしなくても grep :

files="*.jpg"
regex="[0-9]+_([a-z]+)_[0-9a-z]*"
for f in $files    # unquoted in order to allow the glob to expand
do
    if [[ $f =~ $regex ]]
    then
        name="${BASH_REMATCH[1]}"
        echo "${name}.jpg"    # concatenate strings
        name="${name}.jpg"    # same thing stored in a variable
    else
        echo "$f doesn't match" >&2 # this could get noisy if there are a lot of non-matching files
    fi
done

正規表現は変数に入れたほうがいい。パターンによっては、文字通りに入れると動作しないものもある。

これは =~ これはBashの正規表現マッチ演算子です。という配列に保存されます。 $BASH_REMATCH . 最初のキャプチャグループはインデックス1に、2番目(もしあれば)はインデックス2に、といった具合に格納されます。インデックス0は完全一致です。

アンカーを使用しない場合、この正規表現(および grep は、以下の例やそれ以上のものにマッチします。

123_abc_d4e5
xyz123_abc_d4e5
123_abc_d4e5.xyz
xyz123_abc_d4e5.xyz

2番目と4番目の例を排除するために、正規表現を次のようにします。

^[0-9]+_([a-z]+)_[0-9a-z]*

という文字列が必要です。 開始 を1桁以上の数字で表す。カラットは文字列の先頭を表します。このように正規表現の最後にドル記号を付けると、以下のようになります。

^[0-9]+_([a-z]+)_[0-9a-z]*$

の場合、ドットは正規表現に含まれない文字であり、ドル記号は文字列の終端を表すため、3番目の例も除外されます。4番目の例は、このマッチングに失敗することに注意してください。

もしあなたがGNU grep (2.5以降あたりだと思うのですが、このときに \K 演算子が追加されました)。

name=$(echo "$f" | grep -Po '(?i)[0-9]+_\K[a-z]+(?=_[0-9a-z]*)').jpg

\K 演算子 (可変長ルックビハインド) は直前のパターンにマッチさせますが、マッチした結果は含まれません。固定長の同等の演算子は (?<=) - を使うと、閉じ括弧の前にパターンが含まれます。この場合 \K は、量 子が異なる長さの文字列にマッチする可能性がある場合 (例えば + , * , {2,4} ).

は、その (?=) 演算子は固定長または可変長のパターンにマッチし、"look-ahead" と呼ばれます。また、マッチした文字列は結果に含まれません。

大文字と小文字を区別しないマッチを行うために (?i) 演算子が使用されます。これは、それに続くパターンに影響を与えるので、その位置は重要である。

ファイル名に他の文字が含まれているかどうかで、正規表現を調整する必要があるかもしれません。今回は、部分文字列を取り込むと同時に文字列を連結する例を示していることに注意してください。