web-dev-qa-db-ja.com

sed、awk、またはgawkを使用して、一致するもののみを印刷する方法

Sed、awk、またはgawkを使用して検索と置換などを行う方法に関する多くの例とマニュアルページがあります。

しかし、私の場合、特定の値を抽出するためにテキストファイルに対して実行する正規表現があります。検索と置換を行いたくありません。これはbashから呼び出されています。例を使用してみましょう:

正規表現の例:

.*abc([0-9]+)xyz.*

入力ファイルの例:

a
b
c
abc12345xyz
a
b
c

これは簡単に聞こえますが、sed/awk/gawkを正しく呼び出す方法がわかりません。私がやりたいと思っていたことは、私のbashスクリプトの中にあります:

myvalue=$( sed <...something...> input.txt )

私が試したものは次のとおりです。

sed -e 's/.*([0-9]).*/\\1/g' example.txt # extracts the entire input file
sed -n 's/.*([0-9]).*/\\1/g' example.txt # extracts nothing
95
Stéphane

sed(Mac OS X)は+で動作しませんでした。代わりに*を試し、一致を印刷するためにpタグを追加しました。

sed -n 's/^.*abc\([0-9]*\)xyz.*$/\1/p' example.txt

+なしで少なくとも1つの数字を照合するには、次を使用します。

sed -n 's/^.*abc\([0-9][0-9]*\)xyz.*$/\1/p' example.txt
43
mouviciel

これを行うにはsedを使用できます

 sed -rn 's/.*abc([0-9]+)xyz.*/\1/gp'
  • -n結果の行を出力しません
  • -rこれにより、キャプチャグループparens()
  • \1キャプチャグループの一致
  • /gグローバルマッチ
  • /p結果を出力する

これを簡単にする tool を自分で作成しました

rip 'abc(\d+)xyz' '$1'
32
Ilia Choly

Perlを使用して、これを簡単にしています。例えば.

_Perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/'
_

これによりPerlが実行されます。_-n_オプションは、STDINから一度に1行ずつ読み取り、コードを実行するようPerlに指示します。 _-e_オプションは、実行する命令を指定します。

命令は読み取られた行で正規表現を実行し、一致する場合は最初のブラックのセットの内容を出力します(_$1_)。

これを行うこともできます最後に複数のファイル名。例えば.

Perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/' example1.txt example2.txt

17
PP.

grepのバージョンがサポートしている場合は、-oオプションを出力のみ正規表現に一致する行の一部。

そうでない場合、ここで私が思いつくことができる最高のsedです:

sed -e '/[0-9]/!d' -e 's/^[^0-9]*//' -e 's/[^0-9]*$//'

...これは、数字なしで削除/スキップし、残りの行について、すべての先行および後続の非数字文字を削除します。 (私はあなたの意図は、それを含む各行から番号を抽出することだと推測しています)。

次のような問題:

sed -e 's/.*\([0-9]*\).*/&/' 

.... または

sed -e 's/.*\([0-9]*\).*/\1/'

... sedは「貪欲な」一致のみをサポートするということです...最初の。*は残りの行と一致します。否定文字クラスを使用して貪欲でない一致を達成できない場合、またはPerl互換またはその正規表現に対する他の拡張機能を備えたsedのバージョンを使用する場合を除き、パターンスペース(行)。

5
Jim Dennis

awkmatch() とともに使用して、キャプチャされたグループにアクセスできます。

_$ awk 'match($0, /abc([0-9]+)xyz/, matches) {print matches[1]}' file
12345
_

これは、パターン_abc[0-9]+xyz_との一致を試みます。そうする場合、最初の項目がブロック_[0-9]+_である配列matchesにスライスを保存します。 match()は、そのサブストリングが始まる文字位置、またはインデックスを返すため(1がストリングの先頭から始まる場合)printアクションをトリガーします。


grepを使用すると、後読みと先読みを使用できます。

_$ grep -oP '(?<=abc)[0-9]+(?=xyz)' file
12345

$ grep -oP 'abc\K[0-9]+(?=xyz)' file
12345
_

これは、abcおよびxyz内で発生するパターン_[0-9]+_をチェックし、数字のみを出力します。

3
fedorqui

Perlは最もクリーンな構文ですが、Perlがない場合(常にあるとは限りません)、gawkと正規表現のコンポーネントを使用する唯一の方法はgensub機能を使用することです。

gawk '/abc[0-9]+xyz/ { print gensub(/.*([0-9]+).*/,"\\1","g"); }' < file

サンプル入力ファイルの出力は

12345

注:gensubは正規表現全体(//の間)を置換するため、置換の番号の前後のテキストを削除するには、([0-9] +)の前後に。*を配置する必要があります。

2
Mark Lakata

行を選択する場合は、不要なビットを削除します。

egrep 'abc[0-9]+xyz' inputFile | sed -e 's/^.*abc//' -e 's/xyz.*$//'

基本的にegrepで必要な行を選択し、sedを使用して数値の前後のビットを取り除きます。

こちらで実際に動作を確認できます:

pax> echo 'a
b
c
abc12345xyz
a
b
c' | egrep 'abc[0-9]+xyz' | sed -e 's/^.*abc//' -e 's/xyz.*$//'
12345
pax> 

更新:明らかに、実際の状況がより複雑な場合、REを修正する必要があります。たとえば、開始時と終了時に常にゼロまたはそれ以上の非数値に単一の数値が埋め込まれている場合:

egrep '[^0-9]*[0-9]+[^0-9]*$' inputFile | sed -e 's/^[^0-9]*//' -e 's/[^0-9]*$//'
1
paxdiablo