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進数と見なされません。これは、シェルがゼロで埋められた10進数(日付/時刻、ファイル名など)をゼロで埋められた10進数よりも高速に処理するためです。 8進数。
しかし、POSIX 仕様ではこれを 8 進数で処理しなければならず、ほとんどのシェルではこれを無視します (標準の基盤となるシェルの元の実装ではそうしなかったからです)。しかし、PASC説明リクエストこれは、ほとんどのシェルが動作を変更し始めたことをより明確に示しています(ksh93、そしてzsh
、復元されたが)、大きな痛みを引き起こします。
見たらksh93 リリース履歴を使用すると、プレフィックスがゼロの数字を8進数として扱う機能がオンまたはオフになっていることがわかります。今日でも算術式では、010は((...))
or内に8がありますが、$((...))
他のほとんどの場所(let '...'
、array[...]
および[[ ... -eq ... ]]
...を含む)では10であることがわかりますprintf
。set -o posix
ほとんどの場所を8にし、注目すべき例外の1つはprintf
...。
zshはPOSIXシェルだと主張したことがないので、新しいオプションが追加されました(octal_zeroes
)2000年にはsh
シミュレーションでアクティブになりましたが、そうでない場合はアクティブになりませんでした。
A printf
2001年後半に追加最初に使用されたstrtod()
テキストを数字に変換することで、前にゼロの数字は8進数で処理されますが、後でksh93などの算術式を受け入れるように変更されるため、optionsの適用を受けます。 )をoctal_zeroes
許可します。)、...0b10010
12#A001
2#10010
1_000_000
したがって、zsh
8進数をに渡すには、printf
次のオプションを使用します。
- 先行ゼロをシミュレート
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
コメントの議論の後に導入されました。