printf가 축소되는 이유는 무엇입니까?


54

다음과 같은 간단한 스크립트를 실행하면

#!/bin/bash
printf "%-20s %s\n" "Früchte und Gemüse"   "foo"
printf "%-20s %s\n" "Milchprodukte"        "bar"
printf "%-20s %s\n" "12345678901234567890" "baz"

다음을 인쇄합니다.

Früchte und Gemüse foo
Milchprodukte        bar
12345678901234567890 baz

즉, 움라우트가있는 텍스트 (예 :) ü는 움라우트 당 한 문자 씩 "줄어 듭니다".

확실히, 나는 어딘가에 잘못된 설정이 있지만 어떤 것이 될 수 있는지 알 수 없습니다.

파일 인코딩이 UTF-8 인 경우 발생합니다.

인코딩을 latin-1로 변경하면 정렬이 정확하지만 움라우트가 잘못 렌더링됩니다.

Frchte und Gemse   foo
Milchprodukte        bar
12345678901234567890 baz

14
printf가 UTF-8 및 기타 멀티 바이트 문자셋을 알고 있어야합니까?
frostschutz

16
문자가 아닌 바이트 수를 계산하는 것처럼 보입니다. echo Früchte und Gemüse | wc -c -m차이점을 참조하십시오 .
Stephen Kitt

7
@frostschutz Zsh의 printf입니다.
Stephen Kitt

10
네, printf가 (적어도) UTF-8을 알고있을 것으로 기대합니다.
René Nyffenegger

12
글쎄, 그렇지 않다. 힘든 행운. ;-)
frostschutz

답변:


87

POSIX는 필요 printf 의를 %-20s측면에서 그 (20)를 계산하는 바이트 하지 문자 로 그 거의 의미에도 불구하고 printf인쇄하는 것입니다 텍스트를 (토론 참조 형식, 오스틴 그룹에서 (POSIX) 및 bash메일 링리스트).

printf의 내장 bash및 대부분의 다른 POSIX 쉘은 명예.

zshsh에뮬레이션 에서도 바보 같은 요구 사항을 무시 하므로 printf예상대로 작동합니다. POSIX와 유사한 쉘이 아닌 printf내장에 대해서도 동일합니다 fish.

üUTF-8 인코딩 문자 (U + 00FC)이 불일치를 설명 두 바이트 (0xc3 및 0xbc)로 이루어진다.

$ printf %s 'Früchte und Gemüse' | wc -mcL
    18      20      18

이 문자열은 18 자이며 18 열 ( 입력에서 가장 넓은 행의 표시 너비를보고하기 -L위한 GNU wc확장)이지만 20 바이트로 인코딩됩니다.

에서 zsh또는 fish텍스트가 올바르게 정렬됩니다.

이제 0 너비 (U + 0308과 같은 문자 결합, 분음 부호)와 같은 문자가 있거나 많은 아시아 스크립트 (Tab과 같은 제어 문자는 언급하지 않음)와 같이 두 배 너비를 가지며 zsh정렬되지 않은 문자도 있습니다 제대로.

zsh:

$ printf '%3s|\n' u ü $'u\u308' $'\u1100'
  u|
  ü|
 ü|
  ᄀ|

에서 bash:

$ printf '%3s|\n' u ü $'u\u308' $'\u1100'
  u|
 ü|
ü|
ᄀ|

ksh93%Ls너비를 표시 너비 로 계산 하는 형식 사양이 있습니다.

$ printf '%3Ls|\n' u ü $'u\u308' $'\u1100'
  u|
  ü|
  ü|
 ᄀ|

텍스트에 TAB과 같은 제어 문자가 포함되어 있으면 여전히 작동하지 않습니다. 어떻게 printf탭 장치가 출력 장치에서 얼마나 멀리 떨어져 있고 인쇄를 시작하는 위치를 알아야합니다. 모든 제어 문자가 너비를 갖는 것으로 간주 하지만 백 스페이스 문자 ( (bold )가 작성된 roff출력에서 와 같이)에서 우연히 작동합니다 .XXX\bXksh93-1

다른 옵션으로 시도해 볼 수 있습니다.

printf '%s\t|\n' u ü $'u\u308' $'\u1100' | expand -t3

그것은 일부 expand구현에서 작동합니다 (GNU는 아님).

GNU 시스템에서는 문자 awkprintf계산되는 GNU 를 사용할 수 있습니다 (바이트가 아니라 표시 너비가 아니므로 0- 폭 또는 2- 폭 문자의 경우 OK가 아니라 샘플의 경우 OK).

gawk 'BEGIN {for (i = 1; i < ARGC; i++) printf "%-3s|\n", ARGV[i]}
     ' u ü $'u\u308' $'\u1100'

출력이 터미널로 이동하면 커서 위치 지정 이스케이프 시퀀스를 사용할 수도 있습니다. 처럼:

forward21=$(tput cuf 21)
printf '%s\r%s%s\n' \
  "Früchte und Gemüse"    "$forward21" "foo" \
  "Milchprodukte"         "$forward21" "bar" \
  "12345678901234567890"  "$forward21" "baz"

2
맞지 않습니다. ücaracter는 다음과 같이 구성 될 수 u+ ¨3 바이트이다. 질문의 경우 2 자로 인코딩되지만 모두 ü똑같이 생성되는 것은 아닙니다 .
Ismael Miguel

6
@IsmaelMiguel u\u308은 하나의 글리프 / 그래프 / 그래프-클러스터 에 대해 두 개 이상의 문자 (유닉스 / wc -m센스에서)이며 이미 언급되어 있으며이 답변에 포함되어 있습니다.
Stéphane Chazelas

"printf는 텍스트를 인쇄하는 것이별로 의미가 없습니다"음, printf가 C 문자 (바이트)를 처리한다고 주장 할 수 있습니다. 텍스트 로케일을 다루어서는 안되며 (아마도 멀티 바이트) 문자셋 인코딩을 이해해야하는 부담이 없어야합니다. 그러나이 방어선은 "% s"바이트 잘림으로 인해 "잘못된"텍스트 (잘린 문자)가 발생하지 않아야한다는 (ISO C99) 요구 사항과 충돌합니다. 이 경우 Glibc도 실패합니다 (아무것도 인쇄하지 않습니다). 진짜 혼란. postgresql.org/message-id/…
leonbloy

@leonbloy, 그 C의 감각을 만들 수도 있습니다 printf(3)(당신이 그것에 대해 감사를 언급하고 그 C99 요구 후 거의 의미)가 아니라 printf(1)문자로 모든 쉘 운영자 또는 다른 텍스트 유틸리티 거래와 같은 유틸리티 (또는 수정하고 또한 문자 처리 같은 wc가지고있는 -m(동안 -c머물렀다 바이트 ) 또는 cut그이있어 -b후에는 -c) 바이트보다 다른 것을 의미 할 수있다.
Stéphane Chazelas

바이트가 아닌 문자를 사용하더라도 열을 정렬하는 데 적합하지 않습니다. 각 문자가 차지하는 터미널 셀 수는 문자 (0-2)에 따라 다릅니다.
R ..

10

인코딩을 latin-1로 변경하면 정렬이 정확하지만 움라우트가 잘못 렌더링됩니다.

Frchte und Gemse   foo
Milchprodukte        bar
12345678901234567890 baz

사실, 아닙니다. 그러나 터미널은 라틴어 1을 사용하지 않으므로 움라우트보다는 정크를 얻습니다.

iconv를 사용하여이 문제를 해결할 수 있습니다.

printf foo bar | iconv -f ISO8859-1 -t UTF-8

(또는 그냥 iconv로 파이프 된 전체 쉘 스크립트를 실행하십시오)


3
이것은 유용한 의견이지만 핵심 질문에 대한 답변은 아닙니다.
gerrit

1
@gerrit 어떻게 그렇게? latin1로 인쇄 할 때 printf가 올바른 경우 latin1로 인쇄하고 나중에 UTF-8로 변환합니까? 핵심 질문에 대한 올바른 해결책 인 것 같습니다.
Wouter Verhelst

1
핵심 질문은 "왜 움라우트가 줄어들고 있습니까?"입니다. 다른 답변에서와 같이 대답은 "utf-8을 지원하지 않기 때문에"입니다. 움라우트가 왜 잘못 렌더링 되는지 또는 움라우트 렌더링을 어떻게 해결할 수 있는지 묻지 않습니다 . 어느 쪽이든, 당신의 제안은 iso8859-1로만 표현 될 수있는 utf-8의 부분 집합에 유용합니다.
gerrit

4
@WouterVerhelst, 그래도 1 바이트 문자셋으로 인코딩 할 수있는 텍스트에만 적용 할 수 있습니다.
Stéphane Chazelas

3
나도 "왜 그런지 알기 만하면 잘못된 결과를 신경 쓰지 않는다"는 것이 아니라 "어떻게 올바른 결과를 얻을 수 있습니까?"
Mr Lister
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.