次のような行を含むファイルがあります
proto=tcp/http sent=144 rcvd=52 spkt=3
proto=tcp/https sent=145 rcvd=52 spkt=3
proto=udp/dns sent=144 rcvd=52 spkt=3
proto の値tcp/http
、つまりtcp/https
、udp/dns
、を抽出する必要があります。
これまでこれを試しましたgrep -o 'proto=[^/]*/'
が、値を としてしか抽出できませんでしたproto=tcp/
。
答え1
ではgrep -o
、抽出したいものと正確に一致させる必要があります。proto=
文字列を抽出したくないので、一致させるべきではありません。
tcp
またはudp
、スラッシュと空でない英数字の文字列が続くものに一致する拡張正規表現は、
(tcp|udp)/[[:alnum:]]+
これをデータに適用すると次のようになります。
$ grep -E -o '(tcp|udp)/[[:alnum:]]+' file
tcp/http
tcp/https
udp/dns
文字列で始まる行に対してのみこれを行うようにするには、次の操作を実行しますproto=
。
grep '^proto=' file | grep -E -o '(tcp|udp)/[[:alnum:]]+'
を使用するとsed
、=
最初の空白文字の前と後のすべてを削除します。
$ sed 's/^[^=]*=//; s/[[:blank:]].*//' file
tcp/http
tcp/https
udp/dns
文字列で始まる行にのみこれを行うようにするには、上記proto=
と同じ前処理ステップを挿入するか、次のようにします。grep
sed -n '/^proto=/{ s/^[^=]*=//; s/[[:blank:]].*//; p; }' file
ここでは、 オプションを使用してデフォルトの出力を抑制し-n
、行が に一致する場合にのみ置換と行の明示的な出力をトリガーします^proto=
。
ではawk
、デフォルトのフィールド区切り文字を使用し、最初のフィールドを で分割して=
、その 2 番目のビットを出力します。
$ awk '{ split($1, a, "="); print a[2] }' file
tcp/http
tcp/https
udp/dns
文字列で始まる行にのみこれを行うようにするには、上記proto=
と同じ前処理ステップを挿入するか、次のようにします。grep
awk '/^proto=/ { split($1, a, "="); print a[2] }' file
答え2
GNU grep (オプション-P
) を使用している場合は、次を使用できます。
$ grep -oP 'proto=\K[^ ]*' file
tcp/http
tcp/https
udp/dns
ここではproto=
、正しい列を抽出していることを確認するために文字列を照合しますが、その後、フラグを使用して出力からそれを破棄します\K
。
上記では、列がスペースで区切られていることを前提としています。タブも有効な区切り文字である場合は、\S
空白以外の文字を一致させるために を使用します。コマンドは次のようになります。
grep -oP 'proto=\K\S*' file
proto=
などの部分文字列である一致フィールドに対しても保護したい場合はthisisnotaproto=tcp/https
、次のように単語境界を追加できます\b
。
grep -oP '\bproto=\K\S*' file
答え3
使用方法awk
:
awk '$1 ~ "proto" { sub(/proto=/, ""); print $1 }' input
$1 ~ "proto"
proto
最初の列にある行に対してのみアクションを実行するようにします
sub(/proto=/, "")
proto=
入力から削除します
print $1
残りの列を印刷する
$ awk '$1 ~ "proto" { sub(/proto=/, ""); print $1 }' input
tcp/http
tcp/https
udp/dns
答え4
もう一つのgrep
解決策:
grep -o '[^=/]\+/[^ ]\+' file
sed
一致したキャプチャ グループのみを印刷する同様の例:
sed -n 's/.*=\([^/]\+\/[^ ]\+\).*/\1/p' file