awkフィールド区切り文字が一貫して機能しないのはなぜですか?

awkフィールド区切り文字が一貫して機能しないのはなぜですか?

awkとssの出力を使用して4番目の列を印刷しようとしています。時にはうまくいきますが、時には列を誤ってマージしたり分割したりすることがあります。いくつかの異なるFSオプションを試しましたが、これにはフィールドヘッダーにスペースが含まれているため、2つ以上のスペースがあります。

これにより、5番目の列と空のヘッダーが提供されます。

$ ss -tn
State   Recv-Q    Send-Q                Local Address:Port                   Peer Address:Port     
ESTAB   0         36                     172.31.19.34:22                   172.115.128.85:64478    
ESTAB   0         0             [::ffff:172.31.19.34]:80          [::ffff:172.115.128.85]:65446    


$ ss -tn | awk -F '[[:space:]][[:space:]]+' '{print $4}'

172.115.128.86:64478 
[::ffff:172.115.128.86]:65446 

ここで同じコマンドを使用すると、私が望む4番目の列が提供されます。

$ ss -tn
State     Recv-Q      Send-Q              Local Address:Port               Peer Address:Port       
ESTAB     0           36                   172.31.19.34:22               172.115.128.85:64478   

$ ss -tn | awk -F '[[:space:]][[:space:]]+' '{print $4}'
Local Address:Port
172.31.19.34:22

おそらくより簡単になることはわかっていますが、追加の処理をしたいのでcut使用しています。awk

詳細を追加:ssがなぜこのIPv6スタイルのアドレスを表示するのかわかりません。これは私のラップトップからApacheサーバーへの接続ですが、私のラップトップにはIPv6アドレスがありません。

答え1

〜のようにムルヒントを与えるコメントawk働き続けることができます。変更できるのは出力間隔ですss

結果ss -nt1は7つの列を出力し、タイトルはState、、、、、、、、です。4番目と5番目の列はコロン()で区切られています。 6番目と7番目の列も同じです。他のすべてのコンテンツはスペース文字で区切られます。 すべての列は、ソートが必要なスペースで埋められます。 4番目と6番目のパディングは左側にあり、他のすべてのパディングは右側にあります。Recv-QSend-QLocal AddressPortPeer AddressPort:

追加のパディングが発生する可能性があります。

  1. 出力がss -nt端末に渡される場合:

    1. その行の最小長(各フィールドの最長内容と最小間隔(6文字)の合計として計算されます)が端末幅より小さい場合、各行は均等にパディングされて端末幅に拡張されます。スペースがあるすべての列。

    2. それ以外の場合、行は破棄され、フィールドは行に沿って並べ替えられます(上記のように端子の幅まで埋められます)。

  2. 出力がss -nt端末に渡されない場合(たとえば、通常のファイルにパイプまたはリダイレクトされる場合)、行の実際の長さは少なくとも80の倍数で定義され、これは上記で定義された最小長よりも高くなります。すべての列は、合計行長(80、160、240、...文字2)を達成するために空白で均等に埋められます。

したがって、2つの列が2つ以上の空白に分割されるという保証はないため、分割時にシーケンスを信頼できなくなります。

ss -tnそれにもかかわらず、列ヘッダーは既知で固定されており、その列にはヘッダー以外のスペースを含めないでください

ss -nt | sed '
  1 s/[ ]Address:/_Address|/g           # Remove the known spaces from column
                                        # headers; also, change ":" into "|"
  s/:\([^:|]*[ ]\)/|\1/g                # Change the colons used as separators
                                        # into vertical bars "|", to avoid
  s/:\([^:|]*\)$/|\1/g                  # confusion with those in IPv6s
' | awk -v FS='\\||[ ]+' -v OFS=":" '   # Split on sequences of one or more
  { print $4,$5 }                       # spaces OR on any vertical bar
'

これにより、コロンで区切られた4番目と5番目の列(ローカルアドレスとポート)のみが印刷されます。デフォルトの単一の空白以外のフィールド区切り文字を使用すると、awk7つではなく8つの列が認識され、これを実行すると、最後の列の右側に1つ以上の空白が埋められ、行の末尾に印刷され{ $1=$1; print; }ます。OFS


1他のオプション(例えば、、、-i-e-m出力を大幅に変更しますss。簡潔さと明確さのために、私たちはこの正確な命令に焦点を当てます。
2近似であり、正確ではない可能性があります。ただし、これはこの質問/回答の要点とは関係ありません。
3もちろん、これは保証されておらず、私たちは意図的にすべてのまれな状況に対処しようとしません。

答え2

awkフィールド区切り文字が一貫して機能しないのはなぜですか?

はい、信頼できないのは出力の空白の数ですss

4列、それが私が望むものです。

次にヘッダー(-H)を削除し、4番目の列を選択します。

$ ss -taH | awk '{print $4}'
172.31.19.34:22
[::ffff:172.31.19.34]:80

ヘッダーは固定されているため、必要に応じてもう一度追加してください。

$  echo "Local Address:Port"
Local Address:Port

完全なコマンド:

$ echo "Local Address:Port"; ss -tnH | awk '{print $4}'
Local Address:Port
172.31.19.34:22
[::ffff:172.31.19.34]:80

はい、コンピュータには常にIPv6アドレスがあります。必要でない場合は、IPv4アドレスをリクエストしてください。

$ ss -tnH4 | awk '{print $4}'
172.31.19.34:22

関連情報