元の文字列は次のとおりです。
str-str001-002_01
str-str005-006_05
数字の前と下線の後の文字列を抽出したいので、
str-str_01
str-str_05
sedがパターンを次のグループに分けることができたことを覚えています。
sed -n 's/\(^.*\)\([0-9]-[0-9]\)\(.*$\)/\1\3/p'
しかし、次のように印刷されます。
str-str0002_01
それから[0-9]が数字だけであることを覚えて、+記号や*記号を使ってみました。その後、空の結果を提供します。
PS:使用して
echo 'str-str001-002_01' | sed -n 's/\(^.*\)\([0-9]-[0-9]\)\(.*$\)/\2/p'
一致すると見られます1-0
。
その後、次のことを試しました。
echo 'str-str001-002_01' | sed -n 's/\(^.*\)\([0-9]\+-[0-9]\+\)\(.*$\)/\2/p'
最初の2桁だけを残して一致します。
1-002
それでは、どのように一致させますか?001-002
答え1
これにより、希望の出力が提供されます。
sed -nE 's/^([^0-9]*).*_([^_]+)$/\1_\2/p'
例の出力
str-str_01
str-str_05
説明する
sed -nE 's/…/…/p'
- EREを使用し、一致しない限り行を印刷しないでください。^
- 行の先頭に固定([^0-9]*)
- できるだけ長くパターンを一致させる。つまり、数字以外の文字は少なくとも1つ必要です。.*_
- できるだけ一致します(一致するものは含まれません)。その後に「_
」が続きます。([^_]+)
- 下線ではなく、可能な限り長いパターンと一致します(最小文字)。$
- ラインの最後までアンカー\1_\2
- 行全体を最初の(…)
一致項目 "_
"と2番目の(…)
一致項目に置き換えます。
あなたの試みが期待どおりに機能しないのは、(*
および+
)が貪欲だからです。以前の原子に一致するできるだけ多くの文字を消費します。したがって、(.*)([0-9]+)
同様のEREに適用されたEREの場合、消費されてマッチが残りますabc123
。 「必要です。.*
abc12
[0-9]+
3
数字ではありません"最初の一致に制限:([^0-9]*)([0-9]+)
get abc
sum 123
。
答え2
$ cat file
str-str001-002_01
str-str005-006_05
$ sed 's/[0-9]\{3\}-[0-9]\{3\}//' file
str-str_01
str-str_05
NNN-NNN
ここで代替コマンドは、3桁の数字を一致させて削除することですNNN
。
マッチ最後のもの1,
次の代わりに使用される番号3
:
$ sed 's/[0-9]\{1,\}-[0-9]\{1,\}//' file
str-str_01
str-str_05
これは+
拡張正規表現での使用に対応します。デフォルトで使用される正規表現sed
は「デフォルト」正規表現であり、+
リテラルプラス文字と一致します。ほとんどのsed
実装は拡張式もサポートしています-E
。
$ sed -E 's/[0-9]+-[0-9]+//' file
str-str_01
str-str_05
*
たとえば、これはダッシュ(周囲の数字がゼロ)[0-9]*-[0-9]*
と一致するため、機能しません。str-str
ライン全体を一致させ、維持したい部分をキャプチャする必要があると思う場合は、そうすることもできます。次のコマンドは、下線を含む数字ではなく、最初の数字と最後の数字をキャプチャします。
$ sed 's/\([^0-9]*\).*\(_.*\)/\1\2/' file
str-str_01
str-str_05
しかし、IMHO これは解読するのが少し難しく、質問で述べられていない文字列の始まりと終わりを想定しています。たとえば、先頭には削除する数字の前に数字を含めることはできません。文字列の末尾は次のようになります。最後文字列の対応する部分に複数のアンダースコアがある場合は、削除する数字の後にアンダースコアを付ける必要はありません。
そのビットだけをキャプチャしないように、いつでもこの式を追加できますが、NNN-NNN
これにより式を理解するのが難しくなります。