web-dev-qa-db-ja.com

文字列の出現の前後に列を抽出する方法

テキストファイルがあります。それは次のようになります:

www.ac.com has address 6.1.1.146 www.ac.com is an alias for ac.com. www.ac.com is an alias for ac.com.
www.ba.net is an alias for www-bn.gs.ba.com. www-bn.gs.ba.com has address 11.28.11.4 ;; connection timed out; no servers could be reached

has addressの前後の列を抽出し、カンマで区切りたい。だから私は取得したい:

www.ac.com,6.1.1.146
www-bn.gs.ba.com,11.28.11.4

これを行う方法? awk '{print $1,$4}' myfile > newfileを試しましたが、1列目と4列目にあるとは限らないため、うまく機能しませんでした。対象の列はさまざまですが、常にhas addressで区切られています。

2
user9371654

grepsedの使用:

grep -o '[^ ]* has address [^ ]*' | sed 's/ has address /,/'

とても簡単なので、私はこれが好きです。


説明

grepは、次のパターンを見つけた各行の一致する(-o)部分のみを出力します。

  • スペースではない文字([^ ]*)の後にhas addressが続き、その後にスペースではない文字([^ ]*)が続きます。

sedは単にhas address,に置き換えます

3
pLumo

sed

sed -r 's/(.* |^)([^ ]*) has address ([^ ]*)( .*|$)/\2,\3/' myfile > newfile

説明

  • sed -r 's/foo/bar/' myfile > newfile:「拡張正規表現」(-r)でsedを使用するため、以下のキャプチャグループ()をエスケープする必要はありません。 fooの出現箇所をbarに置き換えます。 myfileから読み取り、newfileに書き込みます。
  • (.* |^)([^ ]*) has address ([^ ]*)( .*|$):スペースの前後にある文字列has addressを探します。この前後は、スペースを含まない文字列である必要があり、グループ([^ ]*)でキャプチャする必要があります。先頭の単語の前は、スペース(前に.*)または行の先頭((.* |^))のいずれかである必要があります。次の単語の後には、スペース(その後に.*が続く)、または行の終わり、つまり( .*|$)のいずれかである必要があります。
  • \2,\3:上記の式は行全体をキャプチャするため、2番目と3番目のキャプチャグループ、つまりhas addressの前後の単語に置き換えます。
3
Sparhawk
Perl -nE '/(\S+) has address (\S+)/ and say "$1,$2"' x
2
JJoao

awk

awk -v OFS=, '
  {
    for(i=1;i<NF;i++){
      j=i+1;
      if ($i=="has" && $j=="address") {
        domain=i-1;
        ip=i+2;
        print $domain,$ip;
        break;
      }
    }
  }'

フィールドをループし、「has」が見つかり、次のフィールドが「address」の場合、出力フィールドセパレータとして,を使用して前後のフィールドを出力します。

0
pLumo