sed:一致するグループのみを印刷


133

最後の2つの数値(1つはint、1つはfloat、その後にオプションの空白が続く)を取得して、それらのみを出力したいと思います。

例:

foo bar <foo> bla 1 2 3.4

印刷する必要があります:

2 3.4

これまでのところ、私は次のとおりです。

sed -n  's/\([0-9][0-9]*[\ \t][0-9.]*[\ \t]*$\)/replacement/p' 

くれます

foo bar <foo> bla 1 replacement

ただし、グループ1に置き換えようとすると、行全体が印刷されます。

sed -n  's/\([0-9][0-9]*[\ \t][0-9.]*[\ \t]*$\)/\1/p' 

グループ内の正規表現に一致する行のセクションのみを印刷するにはどうすればよいですか?

回答:


138

行全体と一致するため.*、正規表現の先頭にa を追加します。これにより、行全体がグループの内容で置き換えられます

echo "foo bar <foo> bla 1 2 3.4" |
 sed -n  's/.*\([0-9][0-9]*[\ \t][0-9.]*[ \t]*$\)/\1/p'
2 3.4

38
-rまたは `--regexp-extended`オプションを追加する必要がありました。そうしないと、invalid reference \1 on s 'コマンドのRHS` エラーが発生しました。
Daniel Sokolowski、2014

15
@DanielSokolowski (andの)代わりに\(and を使用すると、そのエラーが発生すると思います\)
ダニエルダラボス2015年

3
また.*、抽出したい文字列が常に行末にあるとは限らない場合は、正規表現の最後に必ず追加してください。
Teemu Leisti 2017年

3
.*貪欲であり、sedには貪欲がないため、これは私にとっては機能しません.*?
sondra.kinsey

@DanielDarabosだけの言及()Ubuntuの16.04でエラーが発生しません。したがって、このコメントは古くなっていると思います。
Li haonan

72

grepは抽出に適したツールです。

あなたの例とあなたの正規表現を使用して:

kent$  echo 'foo bar <foo> bla 1 2 3.4'|grep -o '[0-9][0-9]*[\ \t][0-9.]*[\ \t]*$'
2 3.4


grep -oは、msysgitを実行しているシステムでは移植されませんが、sedでは移植されます。
チェンバレン2015年

これをgrepで解決するために先読みと後読みを使用する回答については、@ jozxyqkによってリンクされた質問を参照してください。
Joachim Breitner、2016

パイプされたgrep -o呼び出しでパターンからグループを抽出できます。stackoverflow.com/a/58314379/117471
Bruno Bronosky

12

さらに別のオプションとして、awkを使用します。

echo "foo bar <foo> bla 1 2 3.4" | awk '{ print $(NF-1), $NF; }'

これにより、入力が分割され(ここではSTDINを使用していますが、入力は簡単にファイルになる可能性があります)、最後から1つ目のフィールド、最後のフィールドの順に出力されます。$NF変数は、スペース上の爆発後に発見されたフィールドの数を保持します。

これの利点は、最後の2つのフィールドだけが機能し続けることを望む限り、最後の2つのフィールドが変更される前に何が変更されても問題ではないことです。


3

cutコマンドは、この正確な状況のために設計されています。区切り文字を「カット」し、出力するチャンクを指定できます。

例えば: echo "foo bar <foo> bla 1 2 3.4" | cut -d " " -f 6-7

結果は次のようになります。 2 3.4

-dは区切り文字を設定します

-fは、出力する「フィールド」の範囲を選択します。この場合は、元の文字列の6〜7番目のチャンクです。のように、範囲をリストとして指定することもできます6,7


特定の列のみを印刷するには、パイプをawk '{ print $2" "$6 }'
nurettin

@nurettin私はあなたのコメントがawkの回答の1つに向けられたのではないかと思います。
carlin.scott 2018年

このページにアクセスしたときに切り取りを試しましたが、制限があることに気付き、この投稿の品質を向上させるためのコメントとして、代わりにawkでより一般的なバージョンを書くことにしました。
ヌレティン2018年

1
ええ、私はそれがawkを含む別の答えに属していると思います。あなたが書いたことを行うためのカットコマンドは次のとおりですcut -d " " -f 2,6
。– carlin.scott

ああ、それは知りませんでした。範囲を指定することしかできないと思いました。それをありがとう。
ヌレッティン

2

これがに適していることを@kentに同意しgrep -oます。パターン内のグループを抽出する必要がある場合は、2番目のgrepでそれを行うことができます。

# To extract \1 from /xx([0-9]+)yy/
$ echo "aa678bb xx123yy xx4yy aa42 aa9bb" | grep -Eo 'xx[0-9]+yy' | grep -Eo '[0-9]+'
123
4

# To extract \1 from /a([0-9]+)b/
$ echo "aa678bb xx123yy xx4yy aa42 aa9bb" | grep -Eo 'a[0-9]+b' | grep -Eo '[0-9]+'
678
9
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.