![awk 필드 구분 기호가 일관되게 작동하지 않는 이유는 무엇입니까?](https://rvso.com/image/154467/awk%20%ED%95%84%EB%93%9C%20%EA%B5%AC%EB%B6%84%20%EA%B8%B0%ED%98%B8%EA%B0%80%20%EC%9D%BC%EA%B4%80%EB%90%98%EA%B2%8C%20%EC%9E%91%EB%8F%99%ED%95%98%EC%A7%80%20%EC%95%8A%EB%8A%94%20%EC%9D%B4%EC%9C%A0%EB%8A%94%20%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C%3F.png)
네 번째 열을 인쇄하기 위해 ss 출력과 함께 awk를 사용하려고 합니다. 때로는 작동하지만 열을 잘못 병합하거나 분할하는 경우도 있습니다. 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 -nt
1은 7개의 열을 출력 하며 그 헤더는 , State
, Recv-Q
, Send-Q
, Local Address
, Port
, Peer Address
입니다 Port
. 네 번째와 다섯 번째 열은 콜론( :
)으로 구분됩니다. 여섯 번째와 일곱 번째도 마찬가지다. 다른 모든 항목은 공백 문자로 구분됩니다.
모든 열은 정렬에 필요한 공백으로 채워집니다. 네 번째와 여섯 번째는 왼쪽에 채워져 있고 나머지는 모두 오른쪽에 있습니다.
추가 패딩이 발생할 수 있습니다.
출력이
ss -nt
터미널로 전달되는 경우:각 필드의 가장 긴 내용과 최소 간격(6자)의 합으로 계산된 줄의 최소 길이가 터미널 너비보다 작은 경우 각 줄은 균등하게 패딩하여 터미널 너비로 확장됩니다. 공백이 있는 모든 열;
그렇지 않으면 줄이 끊어지고 필드가 줄에 걸쳐 정렬됩니다(위와 같이 터미널 너비까지 채워짐).
의 출력이
ss -nt
터미널로 전달되지 않는 경우(예: 파이프로 연결되거나 일반 파일로 리디렉션됨) 줄의 실제 길이는 위에 정의된 최소 길이보다 큰 최소 배수인 80으로 정의됩니다. 모든 열은 결과적으로 80, 160, 240, ... 문자 2 가 되는 전체 줄 길이에 도달하기 위해 공백으로 균등하게 채워집니다 .
따라서 두 열이 두 개 이상의 공백으로 분리된다는 보장이 없으므로 해당 시퀀스를 분할에 신뢰할 수 없게 만듭니다.
ss -tn
그럼에도 불구하고 열 헤더는 알려져 있고 고정되어 있으며 헤더를 제외하고 해당 열에는 공백 3 이 포함되어서는 안 된다는 점을 참고하면 합리적으로 안전한 방식으로 의 출력을 처리할 수 있습니다.
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
'
그러면 콜론으로 구분된 네 번째 및 다섯 번째 열(로컬 주소 및 포트)만 인쇄됩니다. 기본 단일 공백이 아닌 필드 구분 기호를 사용하면 awk
7개가 아닌 8개의 열이 식별되고, 를 수행하면 마지막 열이 오른쪽에 at으로 채워지는 줄 끝에 가 { $1=$1; print; }
인쇄됩니다. OFS
적어도 하나의 공간.
1 다른 옵션(예: -i
, -e
, -m
)은 의 출력을 크게 변경합니다 ss
. 간결함과 명확성을 위해 우리는 이 정확한 명령에만 초점을 맞추겠습니다.
2 대략적이며 부정확할 수도 있습니다. 그러나 이것은 이 질문/답변의 요점과 관련이 없습니다.
3 이는 보장되지 않는 것으로 보입니다. 의도적으로 덜 일반적인 경우를 모두 다루려고 노력하지는 않습니다.
답변2
awk 필드 구분 기호가 일관되게 작동하지 않는 이유는 무엇입니까?
즉, 신뢰할 수 없는 것은 의 출력에 있는 공백의 수입니다 ss
.
네 번째 열은 이것이 제가 원하는 것입니다.
그런 다음 헤더( -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