12

パターンに一致する部分文字列を抽出してファイルに保存したい。文字列の例:

Apr 12 19:24:17 PC_NMG kernel: sd 11:0:0:0: [sdf] Attached SCSI removable disk

この場合、括弧の間の部分を抽出したい[sdf]

grep -e '[$subtext]'括弧内のテキストを変数に保存するようなことをしようとしました。もちろんうまくいきませんが、これに似た方法を探しています。このように正規表現に変数を含めることは非常にエレガントです。どうすればよいですか?

ありがとう!

4

4 に答える 4

13

BASH_REMATCHシェルによって一致したグループを含む配列です。

$ line='Apr 12 19:24:17 PC_NMG kernel: sd 11:0:0:0: [sdf] Attached SCSI removable disk'
$ [[ $line =~ \[([^]]+)\] ]]; echo "${BASH_REMATCH[1]}"
sdf

これをループに入れたい場合は、それを行うことができます。例を次に示します。

while read -r line; do
  if [[ $line =~ \[([^]]+)\] ]] ; then
    drive="${BASH_REMATCH[1]}"
    do_something_with "$drive"
  fi
done < <(dmesg | egrep '\[([hsv]d[^]]+)\]')

このアプローチでは、外部呼び出しがループに入れられないため、シェルは、またはなどの外部プログラムを開始する必要がforkありません。そのため、ここで提供されている他のアプローチよりも間違いなく大幅にクリーンです。execsedgrep

ところで、最初のアプローチ (grep を使用) はそれほど遠くありませんでした。usinggrep -oは、一致する部分文字列のみを出力します。

$ subtext=$(egrep -o "\[[^]]*\]" <<<"$line")

...ただし、これにはキャプチャ内の括弧が含まれるため、100% 正しいわけではありません。

于 2010-04-13T00:49:53.433 に答える
10

おそらく、bash のみを使用するより良い方法がありますが、次のようになります。

echo 'Apr 12 19:24:17 PC_NMG kernel: sd 11:0:0:0: [sdf] Attached SCSI removable disk' \
| sed -s 's/.*\[\(.*\)\].*/\1/'

Jurgen が指摘するように、これは一致しない行に一致します。一致しない行を出力したくない場合は、「-n」を使用してパターンを出力しないようにし、「/p」を使用してパターンが一致した場合に出力します。

| sed -n 's/.*\[\(.*\)\].*/\1/p'
于 2010-04-12T18:23:50.187 に答える
4

正規表現と照合し、グループ化を使用して置き換え、正規表現が一致した場合にのみ印刷します。

sed -n "s/.*\[\(.*\)\].*/\1/p"
于 2010-04-12T19:31:58.507 に答える
1

[]sed は貪欲であるため、データにさらにペアがある場合、sed の回答はデータの一部を見逃してしまいます。grep+tr ソリューションを使用するか、awk を使用できます

$ cat file
[sss]Apr 12 19:24:17 PC_NMG kernel: sd 11:0:0:0: [sdf] Attached SCSI removable disk [tag] blah blah

$ awk -F"[" '{for(i=2;i<=NF;i++){if($i~/\]/){sub("].*","",$i)};print $i}}' file
sss
sdf
tag
于 2010-04-13T00:30:29.193 に答える