web-dev-qa-db-ja.com

最初の2つの一致の間の行ごとのテキストの検索

テキスト付きのファイルがあります:

1861_ASSET-D_T_201702181000-201702181045_HN_
197895_STRING-H_T_201702181000-201702181045_HN_
14512861_FILE-FD_T_201702181000-201702181045_HN

Egrep、awk、またはsedを使用して、最初と2番目に一致する「_」の間にテキストを割り当てるにはどうすればよいですか?

私が欲しい:

ASSET-D
STRING-H
FILE-FD
6
Oleksii

awkを次のパラメーターとともに使用できます。

  • -F "_"-_を区切り文字として使用します
  • '{print $2}'-2番目の要素を出力します

    $ awk -F  "_" '{print $2}' input_file
    ASSET-D
    STRING-H
    FILE-FD
    
10
Yaron
$ sed -r 's/[^_]+_([^_]+)_.*/\1/' file
ASSET-D
STRING-H
FILE-FD

説明

  • -r EREを使用
  • s/old/new/oldnewに置き換えます
  • [^_]+アンダースコアではない文字
  • (some chars)保存some chars後で使用
  • .*任意の数の任意の文字
  • \1保存されたパターン
10
Zanna

他のツールを許可する場合は、cutが最も簡単なソリューションになります。

cut -d _ -f 2 < input.txt > output.txt
9
David Foerster

いくつかのPerlアプローチ:

$ Perl -F_ -lae 'print $F[1]' file 
ASSET-D
STRING-H
FILE-FD

-aはPerlをawkのように動作させ、-Fで指定された文字で各入力行を分割し、結果の各フィールドを配列@Fに保存します。したがって、$F[1]を印刷すると、2番目のフィールドが印刷されます(配列は0からカウントを開始します)。

代わりに:

$ Perl -pe 's/.*?_(.+?)_.*/$1/' file 
ASSET-D
STRING-H
FILE-FD

-pは、「-e」で指定されたスクリプトを実行した後、すべての入力行を印刷することを意味します。 s/from/to/は置換演算子です。 fromtoに置き換えます。ここでは、0個以上の文字(.*)と一致していますが、「貪欲でない」(.*?)にしています。 ?は、最短一致で停止します。したがって、.*?_は最初の_までのすべてに一致します。次の部分(.+?)_は、次の_まで1つ以上の文字と一致し、行の最後(.*)まで他のすべてと一致します。括弧は一致を「キャプチャ」し、演算子の置換側で$1として使用できるようにします。したがって、全体が行全体を括弧内にあるもので置き換えるだけです。


grepでこれを行うこともできます:

$ grep -oP '^.*?_\K[^_]+' file 
ASSET-D
STRING-H
FILE-FD

-oは「一致した各行の一部のみを印刷する」ことを意味し、-P\Kを提供するPerl互換正規表現(PCRE)をオンにします。 \Kは、「この時点までに一致するすべてを無視する」ことを意味します。これは、最初の^.*?_まで_を使用してすべてを一致させ、次に\Kを使用して破棄して印刷されないことを意味します。次に、必要なだけの_文字を必要なだけ([^_]+)必要とします。

6
terdon

pythonワンライナーとして:

python3 -c "[print(l.split('_')[1]) for l in open('f')]"

ここで、'f'は引用符で囲まれたファイルです。例:

python3 -c "[print(l.split('_')[1]) for l in open('/home/jacob/blub')]"

ASSET-D
STRING-H
FILE-FD

説明

for l in open('f')

f 行ごとを読み取り、

l.split('_')[1]

行を区切り文字_で分割し、2番目の文字列を保持します(インデックス[1][0]は最初です)。

print(l.split('_')[1]) 

その後、見つかった文字列を出力します。

6
Jacob Vlijm