awk 필드 구분 기호가 일관되게 작동하지 않는 이유는 무엇입니까?

awk 필드 구분 기호가 일관되게 작동하지 않는 이유는 무엇입니까?

awk 및 ss의 출력을 사용하여 네 번째 열을 인쇄하려고 합니다. 때로는 작동하지만 때로는 열을 잘못 병합하거나 분할하는 경우도 있습니다. 몇 가지 다른 FS 옵션을 시도했는데 여기에는 필드 헤더에 공백이 포함되어 있기 때문에 두 개 이상의 공백이 있습니다.

이렇게 하면 다섯 번째 열과 빈 헤더가 제공됩니다.

$ 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 

여기서 동일한 명령을 사용하면 내가 원하는 네 번째 열이 제공됩니다.

$ 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, Recv-Q, Send-Q, Local Address, Port, Peer Address입니다 Port. 네 번째와 다섯 번째 열은 :콜론( )으로 구분됩니다. 여섯 번째와 일곱 번째 열도 마찬가지입니다. 다른 모든 콘텐츠는 공백 문자로 구분됩니다.
모든 열은 정렬이 필요한 공간으로 채워집니다. 네 번째와 여섯 번째 패딩은 왼쪽에 있고 다른 모든 패딩은 오른쪽에 있습니다.

추가 패딩이 발생할 수 있습니다.

  1. 출력이 ss -nt터미널로 전달되는 경우:

    1. 해당 행의 최소 길이(각 필드의 가장 긴 내용과 최소 간격(6자)의 합으로 계산됨)이 터미널 너비보다 작은 경우 각 행은 균등하게 패딩하여 터미널 너비로 확장됩니다. 공백이 있는 모든 열.

    2. 그렇지 않으면 줄이 끊어지고 필드가 줄을 따라 정렬됩니다(위와 같이 터미널 너비까지 채워짐).

  2. 출력이 ss -nt터미널로 전달되지 않는 경우(예: 일반 파일로 파이프되거나 리디렉션되는 경우) 행의 실제 길이는 최소 80의 배수로 정의되며, 이는 위에 정의된 최소 길이보다 높습니다. 모든 열은 총 행 길이(80, 160, 240, ... 문자 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
'

그러면 콜론으로 구분된 네 번째 및 다섯 번째 열(로컬 주소 및 포트)만 인쇄됩니다. 기본 단일 공백 ​​이외의 필드 구분 기호를 사용하면 awk7개가 아닌 8개의 열이 인식되며, 를 수행하면 마지막 열 오른쪽에 공백이 하나 이상 채워져 행 끝에 인쇄 { $1=$1; print; }됩니다 .OFS


1다른 옵션(예: -i, -e, -m)은 출력을 크게 변경합니다 ss. 간결성과 명확성을 위해 우리는 이 정확한 명령에만 초점을 맞추겠습니다.
2근사치 이며 정확하지 않을 수 있습니다. 하지만 이는 이 질문/답변의 요점과 관련이 없습니다.
3물론 이는 보장되지 않으며 우리는 의도적으로 모든 드문 상황을 다루려고 시도하지 않습니다.

답변2

awk 필드 구분 기호가 일관되게 작동하지 않는 이유는 무엇입니까?

예, 신뢰할 수 없는 것은 출력의 공백 수입니다 ss.

4열, 그것이 내가 원하는 것입니다.

그런 다음 헤더( -H)를 제거하고 네 번째 열을 선택합니다.

$ 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

관련 정보