sh -c 'printf "%d " 024'
bash -c 'printf "%d " 024'
zsh -c 'printf "%d" 024'
위의 출력은 20 20 24
. zsh가 8진수 표기법을 존중하지 않는 이유는 무엇입니까? 이것을 바꿀 수 있는 방법이 있나요?
답변1
zsh
POSIX 셸은 아니며 sh
POSIX 사양이 출시되기 전에 작성되었으며 ksh, csh, tcsh, rc의 기능과 구문을 취하고 자체 기능을 많이 추가했습니다. 구문은 Korn과 거의 유사하지만 이것이 Korn 셸과 완전히 호환된다는 의미는 아닙니다. 어쨌든 이는 sh 언어에 대한 POSIX 호환 인터프리터가 아니며 의도된 것도 아닙니다(적어도 기본 모드에서는 아님).
그러나 여기에는 다른 셸과의 호환성을 향상하고 해당 셸용으로 작성된 코드를 해석하는 데 사용할 수 있는 다양한 에뮬레이션 모드(csh, ksh 및 sh(이전에는 SysV sh를 따르려고 시도했지만 현재는 POSIX sh를 따르려고 함))가 있습니다. 이는 sh 또는 다른 쉘(예: csh, rc, fish, perl, python...)과 독립적인 자체 구문을 가질 수 있으며 여전히 sh용으로 작성된 코드를 해석할 수 있음을 의미합니다.
sh
, csh
또는 (또는 Bourne의 경우) 또는 최신 버전 으로 시작하는 항목으로 호출하면 ksh
해당 시뮬레이션 모드로 들어가지만 일반적으로 사용하는 방식은 아닙니다. 스크립트를 해석하려면 대신 실행해야 합니다.s
b
c
k
--emulate sh/ksh/csh
sh
sh
zsh
zsh에서 sh 코드를 해석하려면 emulate sh
내부에서 실행하여 zsh
시뮬레이션 모드를 전환 sh
하거나 emulate sh -c 'some code'
시뮬레이션에서 해석하기 위해 실행하는 것이 좋습니다 some code
.sh
따라서, 내에서 zsh
:
emulate sh -c 'printf "%d\n" 024'
printf
보다 POSIX 방식으로 작동합니다.
의 경우 printf
, 1986년경에 printf
libc 함수를 통해 C에서 사용할 수 있는 동일한 텍스트 형식 지정 API를 얻기 위한 유틸리티가 Research Unix 버전 9(AT&T Research/Bell Labs에서 제공, 널리 사용되지 않음)에 처음 등장했습니다 printf
.
첫 번째 인수의 형식을 NUL로 구분된 바이트 배열에 대한 포인터와 다양한 유형(포인터, 정수, 이중...)의 추가 인수로 사용 하지만 C
실행 파일은 인수를 문자열로만 사용할 수 있습니다. 따라서 예를 들어 숫자의 형식을 지정하려면 %d
숫자에 대한 텍스트 표현을 제공하고 다시 이진 정수로 변환한 다음 printf
출력을 위해 다시 텍스트로 변환해야 합니다.
내부에V9의 원래 구현, printf
C에서와 동일한 숫자를 인식합니다( dec -123
, +123
, Octal 0123
, hex 0x123
, float 1.2e-2
, Even 'x'
또는 "foo"
(여기서 사용된 첫 번째 문자의 값)).
SVR4(V7의 후속 버전)에는 printf
다음을 수행하는 매우 어리석은 유틸리티도 있습니다.
printf(fmt, argv[2], argv[3], argv[4], argv[5],
argv[6], argv[7], argv[8], argv[9],
argv[10], argv[11], argv[12], argv[13],
argv[14], argv[15], argv[16], argv[17],
argv[18], argv[19], argv[20]);
%s
printf()
따라서 문자열 인수에 대한 포인터만 제공되므로 -type 형식 지정에만 유용합니다 .
POSIX.2(1980년대 후반에 비공개로 작성되어 1992년에 출시됨(아직 무료로 사용할 수 없음))은 명령을 지정합니다 printf
. 이 echo
유틸리티는 이식성이 매우 낮고 신뢰할 수 없기 때문에 대안이 절실히 필요합니다. 어떤 이유에서인지 내장 함수를 사용하는 대신 문자열을 숫자로 변환할 때 C 언어를 참조하여 주로 V9 구현을 기반으로 하는 유틸리티를 지정 ksh
했습니다 .print
printf
POSIX 사양의 기반이 되는 쉘인 ksh88은 내장된 sh
적이 없습니다 printf
(pdksh 복제본도 마찬가지입니다). ksh93에 추가된 옵션 에 대한 별칭 으로 자체 print
내장 함수가 있습니다 .echo
-f
print
printf
print -f
ksh에서 숫자를 입력으로 사용하는 대부분의 내장 함수 또는 구성은 숫자 상수뿐만 아니라 모든 산술 표현식을 허용합니다. 그래서 ksh93에서는
printf '%d\n' '1 + 1'
인쇄됩니다 2
.
이전 버전에서는 printf '%d\n' 010
8 대신 10이 인쇄되었습니다.
ksh 셸 산술 표현식에서 앞에 0이 있는 숫자는 처음에는 8진수로 간주되지 않습니다. 셸이 0으로 채워진 10진수(예: 날짜/시간, 파일 이름)를 0으로 채워진 10진수보다 더 빠르게 처리하기 때문입니다. 8진수.
그러나 POSIX 사양에서는 이를 8진수로 처리해야 하며 대부분의 쉘에서는 이를 무시합니다(표준의 기반이 되는 쉘의 원래 구현에서는 그렇게 하지 않았기 때문입니다). 하지만PASC 설명요청이는 대부분의 쉘이 동작을 변경하기 시작했음을 더욱 명확하게 보여줍니다(ksh93,및 zsh
, 비록 복원되었지만), 큰 통증을 유발합니다.
당신이 보면ksh93 출시 내역를 사용하면 접두사가 0인 숫자를 8진수로 처리하는 기능이 켜져 있거나 꺼져 있음을 알 수 있습니다. 오늘날에도 산술 표현식에서 010은 ((...))
or 안에 8이 있지만 $((...))
대부분의 다른 곳( let '...'
, array[...]
및 [[ ... -eq ... ]]
... 포함) 에서는 10이라는 것을 알 수 있습니다 printf
. set -o posix
대부분의 장소를 8로 만들고,주목할만한 예외 중 하나는... printf
다시 말하지만.
zsh는 POSIX 쉘이라고 주장한 적이 없으므로 단지새로운 옵션이 추가되었습니다 ( octal_zeroes
)2000년에는 sh
시뮬레이션에서 활성화되었지만 그렇지 않은 경우에는 활성화되지 않았습니다.
A printf
2001년 후반에 추가됨처음에 사용된strtod()
텍스트를 숫자로 변환하여 앞에 0이 있는 숫자는 8진수로 처리되지만 나중에 ksh93과 같은 산술 표현식을 허용하도록 변경되므로 options 의 적용을 받으며 더 많은 숫자 형식(예: ksh 스타일 임의 기반 숫자( , ...) 을 octal_zeroes
허용합니다. ), ...0b10010
12#A001
2#10010
1_000_000
따라서 zsh
8진수를 에 전달하려면 printf
다음 옵션을 사용하세요.
- 선행 0을 시뮬레이션
sh
하고 사용합니다.emulate sh -c 'printf %d 024'
- 설정
octalzeroes
옵션:set -o octalzeroes; printf %d 024
- 로컬 범위에서만 동일합니다. (
(){ set -o localoptions -o octalzeroes; printf %d 024; }
여기서는 익명 함수에 있음) 8#oooo
항상 인식되는 기호를 사용하십시오 .printf %d '8#24'
printf
내장 기능을 비활성화 하고 시스템printf
유틸리티가 다음과 같은 POSIX 규격을 준수한다고 가정합니다disable printf; printf %d 024
.- 독립적인 다른 메서드 호출
printf
: ( 시뮬레이션이command printf %d 024
아님 ), ( 시뮬레이션이 아님)sh
=printf %d 024
sh
답변2
command printf ...
표준 printf 유틸리티를 실행 하는 데 사용됩니다 . zsh의 printf에는 POSIX 표준과 충돌하는 자체 인수 해석이 있으며 %d는 인수를 산술 표현식으로 해석하므로 printf %d '8#24'
.
답변3
기본적으로 zsh는 POSIX와 호환되지 않으며 작은 차이도 아닙니다.
이는 zsh를 사용할 때 흔히 발생하는 문제입니다.
노력하다:
zsh --emulate sh -c 'printf "%d\n" 024'
20이 인쇄됩니다
하지만 이는 최신 zsh
버전에서만 작동한다는 점에 유의하세요.
zsh
이전 버전에서도 작동하는 방법을 선호한다면 이를 수행할 수 있는 방법이 있습니다. $HOME/.zshenv
다음 내용으로 파일을 만듭니다 .
if [ -n "$ZSH_EMULATION" ]; then
emulate "$ZSH_EMULATION"
fi
파일이 있는 경우 다음으로 전화할 수 있습니다.
ZSH_EMULATION=sh zsh -c 'printf "%d\n" 024'
이는 모든 버전에 적용됩니다 zsh
.
참고: 현재 관련 텍스트는 ZSH_EMULATION
의견 토론 후 소개되었습니다.