바이트 문자열 길이 대신 '%10s' printf 형식 문자열 길이를 계산하도록 awk에 지시할 수 있습니까?

바이트 문자열 길이 대신 '%10s' printf 형식 문자열 길이를 계산하도록 awk에 지시할 수 있습니까?

다음 출력을 시도해 보십시오 |Ü| X|.

echo 'Ü X' | awk '{printf("|% 2s|% 2s|\n", $1, $2)}'

분명히 awk문자 길이가 아닌 바이트 길이가 계산되므로 Ü개수는 2이고 왼쪽 여백은 필요하지 않습니다 X.

awk중요한 모드에서 실행할 수 있습니까?특징바이트 길이가 아닌 패턴 길이 %<count>s printf입니까?

이것같은 bash문제 가 있습니다printf. 대답이 다르기를 바랍니다. "libc printf로의 통과" :-/

나는 ~였다아니요gawk버전에 관계없이 사용됨우분투22.04(Jammy Jellyfish)가 이미 설치해 주었습니다. gawk요즘은 설치가 불가능할 줄 알았는데 :-/

답변1

GNU awk(다른 awk 변형이 있을 수 있습니다):

$ echo 'Ü X' | LC_ALL='en_US.UTF-8' awk '{printf "|% 2s|% 2s|\n", $1, $2}'
| Ü| X|

배쉬 3.0+(조정해야 할 다른 쉘이 있을 수 있습니다):

$ LC_ALL='en_US.UTF-8' a='Ü' b='X'
$ printf '|%*s%s|%*s%s|\n' "$(( 2 - ${#a} ))" '' "$a" "$(( 2 - ${#b} ))" '' "$b"
| Ü| X|

bash 버전은 버전이 발생하는 환경 뿐만 아니라 LC_ALL실행 중인 셸에서 설정되어야 하므로 호출 셸에서 이를 변경 하지 않으려면 저장/복원해야 합니다. 즉 , 또는 서브셸에서 모든 작업을 수행합니다 . 즉, .${#a}printfawkLC_ALLo="$LC_ALL"; LC_ALL='en_US.UTF-8' ... "$b"; LC_ALL="$o"( LC_ALL='en_US.UTF-8' ... "$b" )

설명하다:

~에서GNU awk 문서:

-b
--characters-as-bytes

gawk가 모든 입력 데이터를 단일 바이트 문자로 처리하도록 합니다. 또한 print 또는 printf를 사용하여 작성된 모든 출력은 단일 바이트 문자로 처리됩니다.

일반적으로 gawk는 POSIX 표준을 따르며 현재 로케일에 따라 입력 데이터를 처리하려고 시도합니다(참조:귀하의 위치는 다양합니다). 여기에는 일반적으로 멀티바이트 문자를 와이드 문자로(내부적으로) 변환하는 작업이 포함되며, 입력 데이터에 유효한 멀티바이트 문자가 포함되어 있지 않으면 문제나 혼란이 발생할 수 있습니다. 이 옵션은 gawk에게 "내 데이터를 삭제하세요!"라고 알리는 쉬운 방법입니다.

적절한 로케일 세트와 함께 GNU awk 5.2.2를 사용하면 멀티바이트 문자를 단일 멀티바이트 문자로 처리합니다.

$ echo 'Ü X' | LC_ALL='en_US.UTF-8' awk '{printf "|% 2s|% 2s|\n", $1, $2}'
| Ü| X|

다른 로캘을 사용하거나 를 사용하는 동안 -b모든 입력은 단일 바이트 문자로 처리됩니다.

$ echo 'Ü X' | LC_ALL='C' awk '{printf "|% 2s|% 2s|\n", $1, $2}'
|Ü| X|

$ echo 'Ü X' | awk -b '{printf "|% 2s|% 2s|\n", $1, $2}'
|Ü| X|

사용 시 -b결과는 로케일과 무관합니다 .

$ echo 'Ü X' | LC_ALL='en_US.UTF-8' awk -b '{printf "|% 2s|% 2s|\n", $1, $2}'
|Ü| X|

$ echo 'Ü X' | LC_ALL='C' awk -b '{printf "|% 2s|% 2s|\n", $1, $2}'
|Ü| X|

~처럼@StéphaneChazelas에서 언급된코멘트, 바라보다printf가 분음 부호를 "축소"하는 이유는 무엇입니까?printf셸의 관련 동작의 경우@Léa Gris의 답변bash 3.0 이상에서 형식화된 출력이 올바르도록 문자 수를 가져오는 것이 좋습니다.

$ a='Ü' b='X' LC_ALL='en_US.UTF-8' 
$ printf '|%*s%s|%*s%s|\n' "$(( 2 - ${#a} ))" '' "$a" "$(( 2 - ${#b} ))" '' "$b"
| Ü| X|

이 기능은 로케일 설정의 영향도 받습니다.

$ LC_ALL='C'
$ printf "|%*s%s|%*s%s|\n" "$(( 2 - ${#a} ))" '' "$a" "$(( 2 - ${#b} ))" '' "$b"
|Ü| X|

당신은 또한 볼 수 있습니다Bash의 문자열 길이Bash에서 문자 길이를 얻는 방법에 대한 추가 정보.

관련 정보