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

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

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

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

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

这是为什么?

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

答案1

printf在某些 shell 中(bash至少kshzsh甚至在sh仿真模式下)的实现理解\xHH为十六进制数HH。然而,这是对标准printf规格

POSIX 标准要求的是printf识别\ooo,其中ooo是一位、两位或三位数字八进制格式参数中的数字以及\0ooo用于%b格式指令的参数中的数字(以匹配echo行为)。

/bin/sh在您的系统上代表的 shell最有可能dash(或者不太可能是yash),与 一起使用时,它理解八进制(像所有标准 shell 一样),但不理解十六进制printf

十六进制数30换算成八进制是60,所以

$ sh -c 'printf "%b\n" "$1"' sh '\060'
0

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

$ sh -c 'printf "\60\n"'
0

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

您的脚本成功打印字符的原因0要么是因为您的#!脚本中有一个 -line 指向bashshell 可执行文件,要么您有根本没有这样的行,而是从交互式 shell 运行脚本bashbash当执行不带行的 shell 脚本时#!,shell 将用来运行bash它(请参阅哪个 shell 解释器运行不带 shebang 的脚本?有关此细节的更多信息)。

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

答案2

当我执行时

$ sh -c printf '\x30'

我明白了

printf: usage: printf [-v var] format [arguments]

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

$ sh -c "printf '\x30\n'"
0

相关内容