Loc*_*ost 5 c printing shell-script ascii printf
如果我用 C 写一行非常简单的代码:
printf("Ascii char for %d is %c\n",65,65);
Run Code Online (Sandbox Code Playgroud)
它只是打印A,因为 ascii 值 65 对应于字符A。但是如果我在shell中使用相同的代码并编写命令
printf "Ascii char for %d is %c\n" 65 65
Run Code Online (Sandbox Code Playgroud)
它将输出显示为Ascii char for 65 is 6. 我期待与 C 语言相同的输出,并且在逻辑上它也应该打印与给定的 ascii 代码对应的字符。
为什么在这些情况下它表现出不同的行为?
在%c接受一个字符串并打印字符串的第一个字符。如果字符串是65,如您的示例中所示,那么它将打印6。
这是由实用程序的 POSIX 规范printf指定的:
c转换说明符的参数可以是包含零个或多个字节的字符串。如果它包含一个或多个字节,则应写入第一个字节,并忽略任何其他字节。如果参数是空字符串,则未指定是不写入任何内容还是写入空字节。如果相应的转换说明符是、 或[...]
b,则参数操作数应被视为字符串cs
这意味着,参数的的%c格式是用C解释不同(其中,一个小的正整数将被转换为一个char),并在所述壳(其中,相同的整数仍然含有几个数字字符的字符串)。不过,格式本身也做同样的事情;它输出一个字节作为一个字符。
然而:
$ printf '%d %b\n' 65 '\0101'
65 A
Run Code Online (Sandbox Code Playgroud)
101 是八进制的 65。并且%b在 POSIX 中指定为
b应支持附加的转换说明符字符 ,如下所示。参数应被视为可以包含<backslash>-escape 序列的字符串。[...]
\0ddd,其中ddd是零、一、二或三位数的八进制数,应转换为具有八进制数指定的数值的字节。
这是一个额外的转换说明符,因为它在标准 C 中不可用。但是在 shell 中需要它,因为我们没有类型变量(在 POSIX shell 中)。
还:
$ printf '%d %b\n' 65 "$( printf '\\0%o\n' 65 )"
65 A
Run Code Online (Sandbox Code Playgroud)
在这里,我们首先将 65 转换为\0ddd使用 格式的八进制数%o,然后在另一个printf使用%b.