性格到价值的作品:
$ printf "%d\n" \'A
65
$
我有两个问题,第一个最重要:
- 我如何取 65 并将其变成 A?
- \'A 使用 printf 将 ASCII 字符转换为其值。语法是特定于printf还是在 BASH 中的其他任何地方使用?(这么小的字符串很难用谷歌搜索。)
一条线
printf "\x$(printf %x 65)"
两条线
set $(printf %x 65)
printf "\x$1"
如果您不介意使用,这是一个awk
awk 'BEGIN{printf "%c", 65}'
这有效(使用八进制值):
$ printf '%b' '\101'
A
即使对于(一些:不要超过 7 个)序列:
$ printf '%b' '\'{101..107}
ABCDEFG
允许任何范围内的(十进制)值的一般构造是:
$ printf '%b' $(printf '\\%03o' {65..122})
ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz
或者您可以使用字符的十六进制值:
$ printf '%b' $(printf '\\x%x' {65..122})
ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz
您还可以使用 xxd 取回字符(使用十六进制值):
$ echo "41" | xxd -p -r
A
也就是说,一个动作与另一个相反:
$ printf "%x" "'A" | xxd -p -r
A
还可以同时使用多个十六进制值:
$ echo "41 42 43 44 45 46 47 48 49 4a" | xxd -p -r
ABCDEFGHIJ
或序列(此处使用 printf 来获取十六进制值):
$ printf '%x' {65..90} | xxd -r -p
ABCDEFGHIJKLMNOPQRSTUVWXYZ
甚至使用 awk:
$ echo 65 | awk '{printf("%c",$1)}'
A
即使对于序列:
$ seq 65 90 | awk '{printf("%c",$1)}'
ABCDEFGHIJKLMNOPQRSTUVWXYZ
对于您的第二个问题,前导引号语法 ( ) 似乎\'A
特定于printf
:
如果前导字符是单引号或双引号,则该值应是单引号或双引号后字符的基础代码集中的数值。
来自https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
一种选择是使用十六进制或八进制表示法直接输入您感兴趣的字符:
printf "\x41\n"
printf "\101\n"
对于这种转换,我使用 perl:
perl -e 'printf "%c\n", 65;'
如果你想保存字符的 ASCII 值:(我在 BASH 中做了这个并且它有效)
{
char="A"
testing=$( printf "%d" "'${char}" )
echo $testing}
输出:65
如果您转换65
为十六进制,则为0x41
:
$ echo -e "\x41"
A
对于大写字母:
i=67
letters=({A..Z})
echo "${letters[$i-65]}"
输出:
C
这是将 65 转换为 A 的另一种方法(通过八进制):
help printf # in Bash
man bash | less -Ip '^[[:blank:]]*printf'
printf "%d\n" '"A'
printf "%d\n" "'A"
printf '%b\n' "$(printf '\%03o' 65)"
搜索man bash
使用\'
(尽管在这种情况下是徒劳的):
man bash | less -Ip "\\\'" # press <n> to go through the matches
这将打印基本 bash 设置的所有“可打印”字符:
printf '%b\n' $(printf '\\%03o' {30..127})
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
以下脚本打印aaa...zzz
(即aaa > aab > aac > ... > zzx > zzy > zzz
)
for i in $(seq 0 25); do FIRST=$(printf \\$(printf '%03o' $[97+$i]) | tr -d '\n'); for f in $(seq 0 25); do SECOND=$(printf \\$(printf '%03o' $[97+$f]) | tr -d '\n'); for g in $(seq 0 25); do THIRD=$(printf \\$(printf '%03o' $[97+$g]) | tr -d '\n'); echo "${FIRST}${SECOND}${THIRD}"; done; done; done
这是一个没有eval也没有$()也没有 `` 的解决方案:
ord () {
local s
printf -v s '\\%03o' $1
printf "$s"
}
ord 65
鉴于没有那么多 1 字节字符,但只有 256 个,它们可以在脚本启动时快速预先计算:
declare -ag CHARS=()
for REPLY in {{0..9},{a..f}}{{0..9},{a..f}}; do
printf -v CHARS[${#CHARS[@]}] "\x$REPLY"
done
(我重用了可丢弃REPLY
变量,但您可以local
在 init 中自己使用function
)
然后...
$ echo "${CHARS[65]}"
A
$ i=65
$ echo "${CHARS[i]}"
A
注意\x00
,它的值在 Bash 中没有被正确处理,因为它是字符串终止符:
$ var=$'qwe\x00rty'
$ echo ${#var}
3
$ echo "<${var}>"
<qwe>
所以,"${CHAR[0]}"
在 Bash 下永远是个问题。
这样,您可以避免每次需要处理一个字符时一次又一次地进行输出捕获、内联文本替换和重新解析;这对于通过或的子进程 IPCxxd
来说更糟。awk
perl