为什么在“dash”下执行 printf 字节格式化会失败?

Mur*_*phy 3 shell bash dash printf

零的 ASCII 十六进制代码是 0x30。因此,您可以通过执行 打印零printf '\x30',它会打印零。

如果将其放入名为 myScript.sh 的 shell 脚本中,然后执行./myScript.sh,它也会打印一个零。

但是,如果您执行sh -c printf '\x30'或 ,sh myScript.sh,您将获得文字字符“\x30”,而不是将其解释为单个字节。

这是为什么?

(已在多台机器上观察到行为,我认为所有这些机器都在运行 bash)。

Kus*_*nda 5

实施printf在一些壳(bashkshzsh,至少;即使在sh仿真模式)理解\xHH为十六进制数HH。然而,这是对标准printf规范的扩展。

POSIX 标准要求的是printf识别\0ddd, 其中ddd是零、一、二或三位数的八进制数。

/bin/sh在您的系统上代表的 shell最有可能dash(或不太可能yash),它可以识别八进制(与所有标准 shell 一样),但在与printf.

十六进制数 30 在八进制中是 60,所以

$ sh -c 'printf "%b\n" "$1"' sh '\060'
0
Run Code Online (Sandbox Code Playgroud)

或者,如果您不想将八进制数作为参数传递,而是想将其用作静态文字:

$ sh -c 'printf "\060\n"'
0
Run Code Online (Sandbox Code Playgroud)

(请注意这里与sh -c您的问题中的语句的区别:整个printf语句,包括其参数,是作为sh实用程序-c选项的选项参数给出的字符串的一部分。我假设您在问题中的内容是一个简单的错字.)

您的脚本设法正确打印零的原因是因为您#!在脚本中有一个指向bashshell 可执行文件的-line ,或者您根本没有这样的行,而是从交互式bashshell运行脚本。该bash外壳,没有执行shell脚本时#!线,将使用bash运行它(见哪个Shell解释程序运行不认领的脚本?想了解更多细节)。

当您使用显式解释器运行脚本时,如在 中sh myScript.sh,该#!行(如果有)将被忽略。


Mur*_*phy 1

当我执行时

$ sh -c printf '\x30'
Run Code Online (Sandbox Code Playgroud)

我明白了

printf: usage: printf [-v var] format [arguments]
Run Code Online (Sandbox Code Playgroud)

它已经提供了一个宝贵的提示,但printf没有获得预期的参数。解决方案是通过将命令参数括在引号中来确保命令参数是单个字符串,而不是多个参数。当然,添加换行符以提高可读性也没有什么坏处:

$ sh -c "printf '\x30\n'"
0
Run Code Online (Sandbox Code Playgroud)