為什麼 zsh printf 不尊重八進製表示法?
sh -c 'printf "%d " 024' bash -c 'printf "%d " 024' zsh -c 'printf "%d" 024'
以上輸出
20 20 24
。為什麼 zsh 不尊重八進製表示法?有沒有辦法改變這個?
zsh
不是 POSIX shell,它是在 POSIX 規範sh
發布之前編寫的,從 ksh、csh、tcsh、rc 中獲取特性和語法,並添加了許多自己的。它的語法在很大程度上類似於 Korn,但這並不意味著它與 Korn shell 完全兼容。無論如何,它不是也不打算成為 sh 語言的 POSIX 兼容解釋器(至少不是在其預設模式下)。然而,它有許多仿真模式(csh、ksh 和 sh(以前嘗試遵循 SysV sh,現在遵循 POSIX sh)),可用於提高與其他 shell 的兼容性並解釋為它們編寫的程式碼。這意味著它可以有自己的語法,與 sh 或任何其他 shell(如 csh、rc、fish、perl、python…)的語法不同,並且仍然能夠解釋為 sh 編寫的程式碼。
如果呼叫為
sh
,csh
, orksh
(或任何以s
(或b
Bourne)c
或k
) 開頭的東西,或在帶有 的較新版本中呼叫--emulate sh/ksh/csh
,它將進入相應的仿真模式,但這不是您通常使用的方式。要解釋sh
腳本,您將執行sh
,而不是zsh
.當你想在zsh中解釋sh程式碼時,你寧願run
emulate sh
insidezsh
來切換仿真模式,你也可以在仿真中執行解釋。sh``emulate sh -c 'some code'``some code``sh
所以,在
zsh
:emulate sh -c 'printf "%d\n" 024'
將以
printf
更 POSIX 的方式執行。至於
printf
,大約在 1986 年,Research Unix 第九版(來自 AT&T Research/Bell Labs,未廣泛使用)中首次出現了一個實用程序,以使用libc 函式printf
獲得與 C 中可用的相同文本格式化 API 。printf
雖然
C
它採用格式第一個參數作為指向以 NUL 分隔的字節數組和不同類型(指針、整數、雙精度…)的額外參數的指針,但執行檔只能將參數作為字元串。因此,要格式化一個數字,例如%d
,需要給它一個數字的文本表示形式,並將其轉換回二進制整數printf
並將其轉換回文本以進行輸出。在V9的原始實現中,
printf
辨識出與 C 語言中相同的數字(dec-123
、+123
、 octal0123
、 hex0x123
、 float1.2e-2
、 even'x'
or"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
-type 格式化有用,因為printf()
它只給出了指向字元串參數的指針。POSIX.2(寫於 80 年代後期(大部分)閉門造車並於 1992 年發布(當時不可免費獲得)),指定了一個
printf
命令。由於該echo
實用程序非常不便攜且不可靠,因此非常需要替代方案。出於某種原因,他們沒有選擇ksh
’printf
主要基於 V9 實現的實用程序,並在將字元串轉換為數字時參考了 C 語言。ksh88,POSIX
sh
規範所基於的 shell 從來沒有printf
內置函式(也沒有它的 pdksh 複製)。它有自己的echo
. 在 ksh93 中添加了一個-f
選項 for以及.print``printf``print -f
在 ksh 中,大多數將數字作為輸入的內置函式或構造都將接受任何算術表達式,而不僅僅是數字常量。所以在 ksh93
printf '%d\n' '1 + 1'
會列印
2
。在早期版本中,
printf '%d\n' 010
將列印 10,而不是 8。在 ksh shell 算術表達式中,最初,帶有前導 0 的數字不被視為八進制,因為在 shell 中,處理 0 填充的十進制數字(如日期/時間、文件名)比處理更常見八進制數。
然而,POSIX 規範確實要求將那些被視為大多數 shell 忽略的八進制(因為標準所基於的 shell 的原始實現沒有)。然而,在PASC 解釋請求使其更清晰之後,大多數 shell 開始改變它們的行為(包括 ksh93和
zsh
,儘管這已被恢復),造成了很大的痛苦。如果您查看ksh93 的發布歷史記錄,您會注意到以 0 為前綴的數字作為八進制的處理一直處於開啟和關閉狀態。即使在今天,你會發現算術表達式中的 010 在
((...))
or中是 8$((...))
,但在大多數其他地方,包括let '...'
、array[...]
和[[ ... -eq ... ]]
…中都是 10printf
。set -o posix
使它在大多數地方變為 8,一個值得注意的例外是……printf
再次。由於 zsh 從未聲稱自己是 POSIX shell,它只是在 2000 年添加了一個新選項 (
octal_zeroes
),在sh
仿真中啟用,但不是在其他情況下。2001 年晚些時候添加了一個
printf
內置函式,最初strtod()
用於將文本轉換為數字,因此將前導 0 的數字視為八進制,但後來更改為接受 ksh93 中的任何算術表達式,因此受octal_zeroes
選項影響,並允許更多的數字格式,例如0b10010
, ksh - 風格的任意基數 (12#A001
,2#10010
…),1_000_000
…因此,在 中
zsh
,要將八進制數傳遞給printf
,選項有:
- 模擬
sh
並使用前導 0: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
仿真中)。