102

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
4

13 に答える 13

45

私の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
于 2009-11-14T08:50:20.117 に答える
39

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

 sed -rn 's/.*abc([0-9]+)xyz.*/\1/gp'
  • -n結果の行を印刷しないでください
  • -rこれにより、キャプチャグループの親をエスケープする必要がなくなり()ます。
  • \1キャプチャグループの一致
  • /gグローバルマッチ
  • /p結果を印刷する

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

rip 'abc(\d+)xyz' '$1'
于 2016-02-03T19:39:12.033 に答える
18

私はperlこれを自分で簡単にするために使用します。例えば

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

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

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

これを行うと、最後に複数のファイル名が表示されます。例えば

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

于 2009-11-14T08:44:04.167 に答える
5

お使いのバージョンがそれをgrepサポートしている場合は、オプションを使用して、正規表現に一致する行の部分のみ-oを印刷できます。

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

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

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

次のような問題:

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

.... また

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

...これはsed「欲張り」一致のみをサポートするということです...したがって、最初の。*は行の残りの部分と一致します。否定された文字クラスを使用して貪欲でない一致を実現できない限り...またはsedPerl互換またはその他の正規表現の拡張機能を備えたバージョンでは、パターンスペース(行)から正確なパターン一致を抽出できません。 )。

于 2009-11-14T10:56:46.013 に答える
5

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

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

これはパターンに一致しようとしますabc[0-9]+xyz。その場合、そのスライスを配列に格納します。配列matchesの最初の項目はブロック[0-9]+です。その部分文字列が始まる文字位置(インデックス)を返すのでmatch() (文字列の先頭から始まる場合は1)、アクションをトリガーしprintます。


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

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

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

[0-9]+これは、パターンが内部で発生したときにabcパターンをチェックしxyz、数字を出力するだけです。

于 2016-08-22T09:01:11.483 に答える
2

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

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

サンプル入力ファイルの出力は次のようになります

12345

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

于 2013-04-29T20:21:53.810 に答える
1

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

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を変更する必要があります。たとえば、開始時と終了時に常に1つの数値が0個以上の非数値内に埋め込まれている場合:

egrep '[^0-9]*[0-9]+[^0-9]*$' inputFile | sed -e 's/^[^0-9]*//' -e 's/[^0-9]*$//'
于 2009-11-14T08:46:20.887 に答える
1

OPの場合は、1行に複数の一致が存在する可能性があることを指定していませんが、Googleトラフィックについては、その例も追加します。

OPの必要性はパターンからグループを抽出することであるため、使用grep -oするには2パスが必要になります。しかし、私はまだこれが仕事を成し遂げるための最も直感的な方法だと思っています。

$ cat > example.txt <<TXT
a
b
c
abc12345xyz
a
abc23451xyz asdf abc34512xyz
c
TXT

$ cat example.txt | grep -oE 'abc([0-9]+)xyz'
abc12345xyz
abc23451xyz
abc34512xyz

$ cat example.txt | grep -oE 'abc([0-9]+)xyz' | grep -oE '[0-9]+'
12345
23451
34512

プロセッサ時間は基本的に無料ですが、人間の可読性は貴重なので、「1年後、これはどうなると思いますか?」という質問に基づいてコードをリファクタリングする傾向があります。実際、私が公にまたは私のチームと共有しようとしているコードについてはman grep、長いオプションが何であるかを理解し、それらを置き換えることさえできます。そのようです:grep --only-matching --extended-regexp

于 2019-10-09T16:11:01.467 に答える
0

なぜマッチグループが必要なのか

gawk/mawk/mawk2 'BEGIN{ FS="(^.*abc|xyz.*$)" } ($2 ~ /^[0-9]+$/) {print $2}'

FSに回線の両端を収集させます。

FSに飲み込まれなかった残り物である$2に数字以外の文字が含まれていない場合、それが印刷するための答えです。

特に注意が必要な場合は、$1と$3の両方の長さがゼロであることを確認してください。

**長さがゼロであることに気付いた後に編集された回答$2は、以前のソリューションをトリップします

于 2021-02-04T00:16:32.983 に答える
0

「」と呼ばれるawkチャネルからの標準的なコードがありますFindAllMatchesが、それでも非常に手動で、文字通り、、、、 moreの長いループを作成してからwhile()、すすぎ、繰り返します。match()substr()substr()

一致した部分だけを取得する方法についてのアイデアを探しているが、各行に複数回一致する、またはまったく一致しない複雑な正規表現がある場合は、次のことを試してください。

mawk/mawk2/gawk 'BEGIN { srand(); for(x = 0; x < 128; x++ ) { 

    alnumstr = sprintf("%s%c", alnumstr , x) 
 }; 
 gsub(/[^[:alnum:]_=]+|[AEIOUaeiou]+/, "", alnumstr) 
                       
                    # resulting str should be 44-chars long :
                    # all digits, non-vowels, equal sign =, and underscore _

 x = 10; do { nonceFS = nonceFS substr(alnumstr, 1 + int(44*rand()), 1)

 } while ( --x );   # you can pick any level of precision you need.
                    # 10 chars randomly among the set is approx. 54-bits 
                    #
                    # i prefer this set over all ASCII being these 
                    # just about never require escaping 
                    # feel free to skip the _ or = or r/t/b/v/f/0 if you're concerned.
                    #
                    # now you've made a random nonce that can be 
                    # inserted right in the middle of just about ANYTHING
                    # -- ASCII, Unicode, binary data -- (1) which will always fully
                    # print out, (2) has extremely low chance of actually
                    # appearing inside any real word data, and (3) even lower chance
                    # it accidentally alters the meaning of the underlying data.
                    # (so intentionally leaving them in there and 
                    # passing it along unix pipes remains quite harmless)
                    #
                    # this is essentially the lazy man's approach to making nonces
                    # that kinda-sorta have some resemblance to base64
                    # encoded, without having to write such a module (unless u have
                    # one for awk handy)


    regex1 = (..);  # build whatever regex you want here

    FS = OFS = nonceFS;

 } $0 ~ regex1 { 

    gsub(regex1, nonceFS "&" nonceFS); $0 = $0;  

                   # now you've essentially replicated what gawk patsplit( ) does,
                   # or gawk's split(..., seps) tracking 2 arrays one for the data
                   # in between, and one for the seps.
                   #
                   # via this method, that can all be done upon the entire $0,
                   # without any of the hassle (and slow downs) of 
                   # reading from associatively-hashed arrays,
                   # 
                   # simply print out all your even numbered columns
                   # those will be the parts of "just the match"

別のを実行する場合OFS = ""; $1 = $1;、4つの引数split()またはを必要とする代わりにpatsplit()、どちらも正規表現のsepsが何であるかを確認するためにgawk固有であるため、$0のフィールド全体がdata1-sep1-data2-sep2-....パターンになります。 、.....$0その間、最初にその行を読んだときとまったく同じように見えます。ストレートアップprintは、読み取り直後に印刷するのと同じバイト単位で行われます。

一度、これで有効なUTF8文字を表す正規表現を使用して極端にテストしました。mawk2が167MBのテキストファイルを処理するのに30秒ほどかかり、すべてが一度に$ 0に読み込まれ、この分割ロジックをクランクすると、NFは約175,000,000になり、各フィールドは1シングルになります。 ASCIIまたはマルチバイトUTF8Unicodeのいずれかの文字。

于 2021-05-05T16:38:56.553 に答える
-1

あなたはシェルでそれを行うことができます

while read -r line
do
    case "$line" in
        *abc*[0-9]*xyz* ) 
            t="${line##abc}"
            echo "num is ${t%%xyz}";;
    esac
done <"file"
于 2009-11-28T01:58:22.147 に答える
-3
gawk '/.*abc([0-9]+)xyz.*/' file
于 2009-11-14T09:18:02.227 に答える
-3

awkの場合。次のスクリプトを使用します。

/.*abc([0-9]+)xyz.*/ {
            print $0;
            next;
            }
            {
            /* default, do nothing */
            }
于 2009-11-14T08:54:58.733 に答える