sed、awk、grepを使用して各行から複数​​のパターンを抽出する方法

sed、awk、grepを使用して各行から複数​​のパターンを抽出する方法

次のテキストファイルがあります。

tech -this is sample and ... 1.2 sample
bla bla bla test tech 1 one two
foo bar foo bar tech and [email protected] 0.1
bar bar bar foo foo tech 10.1.3
tech 7.5 and continue this line
sample_test one two tech 8.0
one two there tech 0.x *sample bla bla
www sample tech 1.3.x foo bar $foo #bar
foobar barbar bla bla tech 5.x
tech testtest 2.0.4x this is sample

サンプルテキストを抽出したい - 次の単語科学技術そしてこのような数字パターン7.5その他のデジタルモード。

(実際には、数値パターンはバージョン管理スタイルのバージョン番号です)

次に、次のように出力を取得します。

tech 1.2
tech 1
tech 0.1
tech 10.1.3
tech 7.5
tech 8.0
tech 0.x
tech 1.3.x
tech 5.x
tech 2.0.4x

答え1

仮説

入力は、スペース文字シーケンス(スペースではなく文字シーケンス)で区切られた文字列を含むテキストファイルです。各行には特定の単語(ランタイムで知られている)が含まれ、その後にはバージョン番号形式の数値文字列が続きます(すぐには必要ありません)。 (明らかにこれは数字で始まるという意味です。)

実行時に引数として検索する単語を指定できる必要があります。たとえば、次の単語を検索するには科学技術、私たちは話すことができなければなりません

word=tech

コマンド(またはスクリプト)を使用するようにします$word。たとえば、「technology」、「nanotech」、「Tech」は一致しないでください。単語には文字、数字、_および(アンダースコア)(句読点、正規表現の特殊文字)のみを含める必要があり、これにより不要な結果が生じる可能性があります。各限られた行に対して、コマンドはスペースで区切られた単語と数字を出力する必要があります。ファイルにこれらの前提条件を満たさない行が含まれている場合(たとえば、必要な単語や数字が含まれていない)、動作は定義されません。特に、これらの故障ラインは単に無視することができる。

以下のすべてのコマンド $wordは上記のように定義されていると仮定します。

注:これらの各コマンドはさまざまな方法で表現できます。場合によっては、その違いはわずかです。

grep

明らかにgrep

私は何をすべきかわかりません。

シンプルgrepで役に立つ

注文する

grep    "\<$word\>\|\<[[:digit:]][[:graph:]]*\>"

以下を含むすべての行と一致します。誰でも単語(\<$word\>)または(\|)数字(\<[[:digit:]][[:graph:]]*\>)。 ([[:graph:]]文字、数字、または句読点、つまりスペースを除くすべての文字を表します。)--colorモードでは、このコマンドの出力は少し面白いです。

        カラー grep 出力

grep -o "\<$word\>\|\<[[:digit:]][[:graph:]]*\>"

一致するすべての文字列を印刷し、一致する文字列のみを印刷します。ひも— 別の行に:

tech
1.2
tech
1
tech
0.1
tech
10.1.3
tech
7.5
tech
8.0
tech
0.x
tech
1.3.x
tech
5.x
tech
2.0.4x

だから私たちはこうします。

grep -o "\<$word\>\|\<[[:番号:]][[:Graphic:]]*\>"(入力ファイル)| sed "/$単語/ { N; s/\n/ / }"
上記の出力を取得して単語をリンクします(科学技術)と次の行(スペースで区切ります):

tech 1.2
tech 1
tech 0.1
tech 10.1.3
tech 7.5
tech 8.0
tech 0.x
tech 1.3.x
tech 5.x
tech 2.0.4x

pcregrep

pcregrep -o1 -o2 --om-separator=' ' "\b($word)\b.*?\b(\d\S*)"

単語を一致そして数字(\b単語の境界、 \d数字、スペースを除くすべての文字)は...グループ\Sからそれぞれをキャプチャします。その後、一致する文字列のみを出力します。ただし、出力キャプチャグループ1と2と言うことができます。当然、文字列の間に何を入れるかを指定してください。()-opcregrep-o1 -o2--om-separator=' '

注:ここでは(貪欲ではない一致)を使用するため、.*?入力行に複数の数字がある場合は、最初の数字が検索されます。他のコマンドは最後のコマンドを探します。

sed

sed -n "s/.*\(\<$word\>\).*[[:blank:]]\(\<[[:digit:]][[:graph:]]*\).*/\1 \2/p"

そのコマンドと同様に、pcregrepこのコマンドはキャプチャグループの文字列と一致し、それを\1 \2

awk

awk -v the_word="$word" '
    {
        w=0             # Index of word
        n=0             # Index of number
        for (i=0; i<=NF; i++) {
                if ($i == the_word) w=i
                if (substr($i,1,1) ~ /[[:digit:]]/) n=i
        }
        if (w>0  &&  n>w) print $w, $n
    }'

the_wordその後、単語()と数字(最初の文字が数字の文字列)を見つけます。見つかったら、順番に印刷します。

注:単語は完全に独立している場合にのみ認識されます。句読点に達すると、他のコマンドも一致します。

The cyber clock goes tech, tock …
This contains the word (tech) …

答え2

以下のコードは望ましい効果を達成する必要があります。

searchword="tech"
(cat << EOF
tech -this is sample and ... 1.2 sample
bla bla bla test tech 1 one two
foo bar foo bar tech and [email protected] 0.1
bar bar bar foo foo tech 10.1.3
tech 7.5 and continue this line
sample_test one two tech 8.0
one two there tech 0.x *sample bla bla
www sample tech 1.3.x foo bar $foo #bar
foobar barbar bla bla tech 5.x
tech testtest 2.0.4x this is sample
EOF
) | grep $searchword |\
grep -o '\b[0-9x][0-9x]*\b\|\b[0-9][0-9]*\.[0-9x][0-9x]*\b\|\b[0-9][0-9]*\.[0-9][0-9]*\.[0-9x][0-9x]*\b' |\
sed "s/^/$searchword /"

あなたを連れてくるだろう

tech 1.2
tech 1
tech 0.1
tech 10.1.3
tech 7.5
tech 8.0
tech 0.x
tech 1.3.x
tech 5.x
tech 2.0.4x

少なくとも

  • 強く打つGNU bash, version 4.4.5(1)-release
  • sedsed (GNU sed) 4.2.2
  • grepgrep (GNU grep) 2.27

この回答が役に立ちました。それ以外の場合は、質問をより明確かつ説明しやすくすることができます。

答え3

grepやsedではこれを得ることはできませんが、Perlは助けます:

$ perl -e 'while($stdin = <>) {@matches = $stdin =~ /(tech)[^0-9]*([0-9x][0-9x.]*)/g; print "@matches\n" if @matches}' < INPUTFILE

これは< INTPUTFILEstdinを介してスクリプトにファイルを入力した場合にのみ機能します。 stdinは他のソース(パイプ、<<<文字列リダイレクトなど)から提供できます。

説明する:

#一致に使用する変数に標準入力(Perl)を割り当てます。
#入力が空の場合(例:EOF)を検出します。
中 ($stdin = ) {
    # @matches 配列に $stdin に一致を割り当てます。
    #/(技術)[^0-9]*([0-9x][0-9x.]*)/g;
    #(tech):「tech」という用語と一致し、()は@matchesに入れます。
    # [^0-9]*: .* があまりにも貪欲であるため、数字ではなく数字と一致すると破棄されます。
    #最後の数字と一致
    #([0-9x] [0-9x.] *):0、0.x、0.9.xなどのパターンを一致させ、()@matchesに入れます。
    @matches = $stdin =~ /(tech)[^0-9]*([0-9x][0-9x.]*)/g;
    # @matchesが空でない場合は、上記の配列を表示します。
    @matchesの場合は、「@matches \ n」を印刷します。
}

ファイルに適用すると、出力は次のようになります。

技術1.2
技術1
技術0.1
技術10.1.3
技術7.5
技術8.0
技術1.3.x
技術5.x
技術2.0.4x

関連情報