zsh printfが8進表記に従わないのはなぜですか?

zsh printfが8進表記に従わないのはなぜですか?
sh -c 'printf "%d " 024'
bash -c 'printf "%d " 024'
zsh -c 'printf "%d" 024'

上記の出力は20 20 24。 zshが8進表記を尊重しないのはなぜですか?これを変える方法はありますか?

ベストアンサー1

zshPOSIXシェルではなく、shPOSIX仕様がリリースされる前に書かれており、ksh、csh、tcsh、rcの機能と構文を取り、独自の機能をたくさん追加しました。構文はKornとほぼ同様ですが、これがKornシェルと完全に互換性があるという意味ではありません。とにかく、これはsh言語のPOSIX互換インタプリタではなく、意図されていません(少なくともデフォルトモードではありません)。

しかし、ここでは他のシェルとの互換性を向上させ、そのシェル用に書かれたコードを解釈するために使用できるさまざまなエミュレーションモード(csh、ksh、sh(以前はSysV shに従おうとしましたが、現在はPOSIX shに従おうとしています) ))があります。これは、shまたは他のシェル(たとえば、csh、rc、fish、perl、python...)とは独立した独自の構文を持つことができ、まだsh用に書かれたコードを解釈できることを意味します。

shcshまたは(またはBourneの場合)、または最新バージョンで始まる項目として呼び出すと、対応するkshシミュレーションモードに入りますが、通常使用する方法ではありません。スクリプトを解釈するには、代わりに実行する必要があります。sbck--emulate sh/ksh/cshshshzsh

zshでshコードを解釈するには、emulate sh内部で実行してzshシミュレーションモードを切り替えるshか、emulate sh -c 'some code'シミュレーションで解釈するために実行することをお勧めしますsome codesh

したがって、内からzsh

emulate sh -c 'printf "%d\n" 024'

printfよりPOSIXの方法で動作します。

の場合printf、1986年頃にprintflibc関数を介してCで使用可能な同じテキスト書式設定APIを取得するためのユーティリティが、Research Unixバージョン9(AT&T Research / Bell Labsで提供され、広く使用されていない)に初めて登場しましたprintf

最初の引数の型をNULで区切られたバイト配列へのポインタと、さまざまな型(ポインタ、整数、二重...)の追加引数として使用しますが、実行可能ファイルはC引数を文字列としてのみ使用できます。したがって、たとえば、数値を書式設定するには、%d数値のテキスト表現を提供し、再びバイナリ整数に変換し、出力のためprintfにテキストに戻す必要があります。

内部にV9のオリジナル実装printfCと同じ数字を認識します(dec -123、、+123Octal 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]);

%sprintf()したがって、文字列引数へのポインタのみが提供されるため、-typeの書式設定にのみ役立ちます。

POSIX.2(1980年代後半に非公開で作成され、1992年にリリースされました(まだ無料では利用できません))は、コマンドを指定しますprintf。このechoユーティリティは、移植性が非常に低く信頼性が低いため、選択肢が非常に必要です。何らかの理由で組み込み関数を使用するのではなく、文字列を数値に変換するときにC言語を参照して、主にV9実装に基づくユーティリティを指定しkshました。printprintf

POSIX仕様の基盤となるシェルであるksh88は組み込まれていshませんprintf(pdkshレプリカも同じです)。 ksh93に追加されたオプションのエイリアスとして、独自の組み込みprint関数があります。echo-fprintprintfprint -f

ksh で数値を入力として使用するほとんどの組み込み関数または構成は、数値定数だけでなく、すべての算術式を受け入れます。だからksh93では

printf '%d\n' '1 + 1'

印刷されます2

以前のバージョンでは、printf '%d\n' 0108の代わりに10が印刷されました。

kshシェル算術式では、先頭に0がある数字は最初は8進数と見なされません。これは、シェルがゼロで埋められた10進数(日付/時刻、ファイル名など)をゼロで埋められた10進数よりも高速に処理するためです。 8進数。

しかし、POSIX 仕様ではこれを 8 進数で処理しなければならず、ほとんどのシェルではこれを無視します (標準の基盤となるシェルの元の実装ではそうしなかったからです)。しかし、PASC説明リクエストこれは、ほとんどのシェルが動作を変更し始めたことをより明確に示しています(ksh93、そしてzsh、復元されたが)、大きな痛みを引き起こします。

見たらksh93 リリース履歴を使用すると、プレフィックスがゼロの数字を8進数として扱う機能がオンまたはオフになっていることがわかります。今日でも算術式では、010は((...))or内に8がありますが、$((...))他のほとんどの場所(let '...'array[...]および[[ ... -eq ... ]]...を含む)では10であることがわかりますprintfset -o posixほとんどの場所を8にし、注目すべき例外の1つはprintf...

zshはPOSIXシェルだと主張したことがないので、新しいオプションが追加されました(octal_zeroes2000年にはshシミュレーションでアクティブになりましたが、そうでない場合はアクティブになりませんでした。

A printf2001年後半に追加最初に使用されたstrtod()テキストを数字に変換することで、前にゼロの数字は8進数で処理されますが、後でksh93などの算術式を受け入れるように変更されるため、optionsの適用を受けます。 )をoctal_zeroes許可します。)、...0b1001012#A0012#100101_000_000

したがって、zsh8進数をに渡すには、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 024sh

おすすめ記事