周囲の文字を出力せずに「sed」と一致する正規表現を抽出する


24

そこにいるすべての「sed」医師に:

行内で一致した正規表現を抽出するために「sed」を取得するにはどうすればよいですか?

言い換えれば、正規表現に対応する文字列だけが、含まれる行の一致しないすべての文字を取り除いたものになります。

以下のような後方参照機能を使用してみました

regular expression to be isolated 
         gets `inserted` 
              here     
               |
               v  
 sed -n 's/.*\( \).*/\1/p 

これは次のようないくつかの式で機能します

 sed -n 's/.*\(CONFIG_[a-zA-Z0-9_]*\).*/\1/p 

'CONFIG_ ....'( '* .h'ファイルにあります)で始まるすべてのマクロ名をきれいに抽出し、それらをすべて1行ずつ出力します

          CONFIG_AT91_GPIO
          CONFIG_DRIVER_AT91EMAC
                   .
                   .   
          CONFIG_USB_ATMEL
          CONFIG_USB_OHCI_NEW
                   .
                 e.t.c. 

しかし、上記のようなもののために内訳

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

これは常に次のような1桁を返します

                 7
                 9
                 .
                 .  
                 6

などの連続した数字フィールドを抽出するのではなく。

              8908078
              89670890  
                 .
                 .  
                 .
               23019   
                 .
               e.t.c.  

PS:これが「sed」でどのように達成されるかについてのフィードバックに感謝します。「grep」と「awk」を使用してこれを行う方法を知ってい
ます単に見落とされた。

回答:


22

正規表現にグループが含まれる場合、文字列を照合する方法は複数ある場合があります。グループを含む正規表現はあいまいです。たとえば、正規表現^.*\([0-9][0-9]*\)$と文字列を考えますa12。次の2つの可能性があります。

  • 一致aに対して.*および2に対して[0-9]*1と一致し[0-9]ます。
  • a1に対して一致し.*、空の文字列に対して[0-9]*; 2と一致し[0-9]ます。

Sedは、他のすべての正規表現ツールと同様に、最も早い最長一致ルールを適用します。最初に、可能な限り長い文字列に対して最初の可変長部分を一致させようとします。文字列の残りを正規表現の残りの部分と一致させる方法が見つかった場合は、問題ありません。それ以外の場合、sedは最初の可変長部分の次の最長一致を試み、再試行します。

ここでは、最長の文字列と最初に一致するのはa1.*あるため、グループはのみ一致し2ます。グループを早めに開始したい場合は、いくつかの正規表現エンジンを使用して.*貪欲さを軽減できますが、sedにはそのような機能はありません。そのため、アンカーを追加してあいまいさを解消する必要があります。.*グループの最初の数字が最初に一致するように、先頭が数字で終わらないように指定します。

  • 数字のグループが行の先頭にない場合:

    sed -n 's/^.*[^0-9]\([0-9][0-9]*\).*/\1/p'
    
  • 数字のグループを行の先頭に置くことができ、sed \?がオプション部分の演算子をサポートしている場合:

    sed -n 's/^\(.*[^0-9]\)\?\([0-9][0-9]*\).*/\1/p'
    
  • 数字のグループが行の先頭にある場合、標準の正規表現の構成にこだわる場合:

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

ちなみに、[0-9]*後続のではなく、最初の数字の後の数字を一致させるのは、同じ最も長い最長一致ルールです.*

行に複数の数字のシーケンスがある場合、プログラムは常にinitialに適用される最も長い最長一致ルールのため、最後の数字のシーケンスを常に抽出することに注意してください.*。最初の数字のシーケンスを抽出したい場合は、前に来るものが数字以外のシーケンスであることを指定する必要があります。

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

より一般的には、正規表現の最初の一致を抽出するには、その正規表現の否定を計算する必要があります。これは常に理論的には可能ですが、否定のサイズは否定しようとしている正規表現のサイズとともに指数関数的に増大するため、これは多くの場合非実用的です。

他の例を考えてみましょう:

sed -n 's/.*\(CONFIG_[a-zA-Z0-9_]*\).*/\1/p'

この例は実際には同じ問題を示していますが、一般的な入力では表示されません。あなたがそれを供給するならhello CONFIG_FOO_CONFIG_BAR、上記のコマンドはプリントするのであってCONFIG_BAR、プリントしませんCONFIG_FOO_CONFIG_BAR

sedを使用して最初の一致を印刷する方法がありますが、少し注意が必要です。

sed -n -e 's/\(CONFIG_[a-zA-Z0-9_]*\).*/\n\1/' -e T -e 's/^.*\n//' -e p

(sedサポート\ns置換テキストの改行を意味すると仮定します。)これは、sedが正規表現の最も早い一致を検索し、CONFIG_…ビットの前に一致するものを一致させないためです。行内には改行がないため、一時的なマーカーとして使用できます。このTコマンドは、先行するsコマンドが一致しなかった場合に放棄するように指示します。

sedで何かを行う方法がわからない場合は、awkに切り替えてください。次のコマンドは、正規表現の最も長い最長一致を出力します。

awk 'match($0, /[0-9]+/) {print substr($0, RSTART, RLENGTH)}'

また、シンプルにしたい場合は、Perlを使用してください。

perl -l -ne '/[0-9]+/ && print $&'       # first match
perl -l -ne '/^.*([0-9]+)/ && print $1'  # last match

22

そうではありませんsedgrep -o、これについてしばしば見落とされがちなものの1つは、私の意見では、このタスクのためのより良いツールです。

たとえばCONFIG_、カーネル構成からすべてのパラメーターを取得する場合は、次を使用します。

# grep -Eo 'CONFIG_[A-Z0-9_]+' config
CONFIG_64BIT
CONFIG_X86_64
CONFIG_X86
CONFIG_INSTRUCTION_DECODER
CONFIG_OUTPUT_FORMAT

連続した数字のシーケンスを取得する場合:

$ grep -Eo '[0-9]+' foo

7
sed '/\n/P;//!s/[0-9]\{1,\}/\n&\n/;D'

...これは大騒ぎなしで行われますがn、右側の置換フィールドのsの代わりにリテラルの改行が必要になる場合があります。ちなみに、.*CONFIG行に一致するものが1つしかない場合にのみ動作します。それ以外の場合は、常に最後のものだけが取得されます。

どのように機能するかの説明についてはこれを見ることができますが、これは別の行に表示されます。

同じ戦略を使用[num]して、行のth番目のオカレンスを取得できます。たとえば、CONFIGマッチが行の3番目である場合にのみCONFIGマッチを出力したい場合:

sed '/\n/P;//d;s/CONFIG[[:alnum:]]*/\n&\n/3;D'

...ただし、CONFIG文字列が出現するたびに少なくとも1つの非英数字で区切られていることを前提としています。

私は-数のこと-これも機能すると思います:

sed -n 's/[^0-9]\{1,\}/\n/g;s/\n*\(.*[0-9]\).*/\1/p

...右辺については以前と同じ注意事項があり\nます。これは最初のものよりも高速ですが、明らかに一般的には適用できません。

CONFIGの場合はP;...;D、パターンで上記のループを使用するか、次のようにします。

sed -n 's/[^C]*\(CONFIG[[:alnum:]]*\)\{0,1\}C\{0,1\}/\1\n/g;s/\(\n\)*/\1/g;/C/s/.$//p'

...これはもう少し複雑で、sedの参照優先順位を正しく並べることで機能します。また、1行ですべてのCONFIG一致を分離します(ただし、以前と同じ仮定を行いますが)-各CONFIG一致は、少なくとも1つの英数字以外の文字で区切られます。GNU sedを使用すると、次のように記述できます。

sed -En 's/[^C]*(CONFIG\w*)?C?/\1\n/g;s/(\n)*/\1/g;/C/s/.$//p'
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.