BASH 打印问题 (printf \\$(printf '%03o' $1))

188*_*885 7 linux bash ascii printf

我用下面要转换INT焦炭INT在bash。但我不明白如何printf \\$(printf '%03o' $1)printf '%d' "'$1"工作。请解释如何 printf \\$(printf '%03o' $1)printf '%d'工作。

#!/bin/bash
# chr() - converts decimal value to its ASCII character representation
# ord() - converts ASCII character to its decimal value

chr() {
  printf \\$(printf '%03o' $1)
}

ord() {
  printf '%d' "'$1"
}

ord A
echo
chr 65
echo
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 10

printf '\101'其中101是一个八进制数,输出具有该值的字节。

当发送到ASCII终端,将被呈现为AA在ASCII字符65(八进制101)和所有兼容ASCII字符集(其包括与EBCDIC那些在某些IBM系统仍然使用之外最现代化的字符集)。

printf \\$(printf '%03o' $1)
Run Code Online (Sandbox Code Playgroud)

应该是这样写的:

printf "\\$(printf '%03o' "$1")"
Run Code Online (Sandbox Code Playgroud)

作为离开参数扩展(如$1),或命令替换($(...))未加引号是 Bourne-like shell 中的 split+glob 运算符,这里不需要

  • printf '%03o' "$1"将数字转换$1为 3 位八进制数
  • printf "\\$(...)"将该八进制附加到 a \\\双引号内变为\)并将其传递给printf以便输出相应的字节值。

请注意,它仅适用于字符集为每个字符一个字节的区域设置(如iso8859-1),或者,在具有多字节字符集的区域设置中,仅适用于值 0 到 127。

bash

printf '%d\n' "'A"
Run Code Online (Sandbox Code Playgroud)

打印字符的 Unicode 代码点A(或至少mbtowc()在 GNU 系统上返回的值至少是 Unicode 代码点)。

其他一些实现(包括独立的 GNUprintf实用程序)会返回字符的第一个字节的值。

对于 ASCII 字符A和基于 ASCII 的系统,这没有任何区别,但对于其他人来说很重要。例如,希腊?字符 (U+03B1) 被编码为:

  • iso8859-7 中的字节 225(标准希腊单字节字符集)
  • UTF-8 中的字节 206 177(类 Unix 系统上最常用的 Unicode 编码)
  • GB18030(Unicode的官方中文编码)中的字节166 193。

Bashprintf '%d\n' "'?"将始终输出945(十六进制为 0x03b1),这是 Unicode 代码点,?与语言环境无关(至少在 GNU 系统上),但其他人可能会根据语言环境返回 225、206 或 166。

您可以从中看到,对于 ASCII 字符(或值 0 到 127),或者在使用所有字符(值 0 到 255)的字符集的语言环境中,这些chrord只是彼此相反iso8859-1

如果ord()要返回 Unicode 代码点,则相反(打印与 Unicode 代码点对应的字符)将是:

chr() {
  printf "\U$(printf %08X "$1")"
}
Run Code Online (Sandbox Code Playgroud)

(假设bash4.3 或更高版本(\UXXXXXXXX在 4.2 中添加,但在 4.3 之前无法对字符 U+0080 到 U+00FF 正常工作))。

然后,在任何语言环境中:

$ ord ?
945
$ chr 945
?
Run Code Online (Sandbox Code Playgroud)

或者ord()返回给定字符编码的字节值(在当前语言环境中):

ord() {
  printf %s "$1" | od -An -vtu1
}
Run Code Online (Sandbox Code Playgroud)

chr()输出这些字节:

chr() {
  printf "$(printf '\\%o' "$@")"
}
Run Code Online (Sandbox Code Playgroud)

然后,例如在 UTF-8 语言环境中:

$ ord ?
 206 177
$ chr 206 177
?
Run Code Online (Sandbox Code Playgroud)

(你ord ?会给945,你chr会为这两个垃圾chr 945chr 206 177)。

或者在语言环境中使用iso8859-7

$ ord ?
 225
$ chr 225
?
Run Code Online (Sandbox Code Playgroud)

(您ord ?将给出 945,但如果在 GNU 系统上printf/usr/bin/printfif替换,则可能给出 225 )。


Lam*_*ert 5

内部printf '%03o' $1返回值$1(即 65)作为八进制值(65 -> 101)。

外部printf \\$(..)打印八进制值表示的字符。

man printf行:

\NNN 字节,八进制值 NNN(1 到 3 位数字)

因为printf '%d' "'$1"您需要指定'以指示$1应将其视为单个字符常量,否则 printf 会引发错误,指示该值是无效数字。然后使用字符常量的值printf以十进制格式打印"%d"