有几种特定于shell的方法可以在字符串中包含"unicode literal".例如,在Bash中,引用的字符串扩展机制$''
允许我们直接嵌入一个不可见的字符:$'\u2620'
.
但是,如果您尝试编写通用的跨平台shell脚本(通常,这可以被截断为"以Bash,Zsh和Dash运行."),这不是便携式功能.
我可以使用如下构造在ASCII表(八进制数字空间)中移植实现任何内容:
WHAT_A_CHARACTER="$(printf '\036')"
...但是,POSIX/Dash printf
仅支持八进制转义.
通过将任务转化为更全面的编程环境,我显然也可以实现完整的Unicode空间:
OH_CAPTAIN_MY_CAPTAIN="$(ruby -e 'print "\u2388"')" TAKE_ME_OUT_TONIGHT="$(node -e 'console.log("\u266C")')"
那么:将这样的字符编码成shell脚本的最佳方法是:
工程在dash
,bash
和zsh
,
显示代码中代码点的十六进制编码,
不依赖于字符串的特定编码(即不通过八进制编码UTF-8字节)
最后,不需要调用任何"重型"解释器.(比方说,运行时间不到0.01秒.)
rici.. 8
如果您安装了Gnu printf
(coreutils
例如,它在debian软件包中),那么您可以通过避免shell的内置来独立于您使用的shell来使用它:
env printf '\u2388\n'
这里我使用Posix-standard env
命令来避免使用printf
内置printf
函数,但如果您碰巧知道在哪里可以直接使用完整的路径,例如
/usr/bin/printf '\u2388\n'
如果你的外部printf
和你的shell内置printf
只实现了Posix标准,你需要更加努力.一种可能性是用iconv
翻译成UTF-8,但在POSIX标准的要求有是一个iconv
命令,它不以任何方式规定标准编码的命名方式.我认为以下内容适用于大多数与Posix兼容的平台,但创建的子shell数量可能足以使其效率低于"重"脚本解释器:
printf $(printf '\\%o' $(printf %08x 0x2388 | sed 's/../0x& /g')) | iconv -f UTF-32BE -t UTF-8
上面使用printf
内置来强制十六进制代码点值为8个十六进制数字长,然后sed
将它们重写为4个十六进制常量,然后printf
再次将十六进制常量更改为八进制表示法,最后另一个printf
将八进制字符常量解释为四个 -可以iconv
作为big-endian UTF-32 输入的字节序列.(用printf
识别\x
转义码的方法会更简单,但Posix不需要它,dash
也不会实现它.)
只要为所有符号提供Unicode代码点(作为整数常量),您就可以使用不经修改的行来打印多个符号(示例执行dash
):
$ printf $(printf '\\%o' $(printf %08x 0x2388 0x266c 0xA | > sed 's/../0x& /g')) | > iconv -f UTF-32BE -t UTF-8 ?? $
注意:正如Geoff Nixon在评论中提到的那样,鱼壳(它无法接近Posix标准,并且据我所知,没有愿意遵守)会抱怨不带引号的%08x
格式参数printf
,因为它期望单词以%
成为职业生涯.因此,如果您使用fish,请在format参数中添加引号.
如果您安装了Gnu printf
(coreutils
例如,它在debian软件包中),那么您可以通过避免shell的内置来独立于您使用的shell来使用它:
env printf '\u2388\n'
这里我使用Posix-standard env
命令来避免使用printf
内置printf
函数,但如果您碰巧知道在哪里可以直接使用完整的路径,例如
/usr/bin/printf '\u2388\n'
如果你的外部printf
和你的shell内置printf
只实现了Posix标准,你需要更加努力.一种可能性是用iconv
翻译成UTF-8,但在POSIX标准的要求有是一个iconv
命令,它不以任何方式规定标准编码的命名方式.我认为以下内容适用于大多数与Posix兼容的平台,但创建的子shell数量可能足以使其效率低于"重"脚本解释器:
printf $(printf '\\%o' $(printf %08x 0x2388 | sed 's/../0x& /g')) | iconv -f UTF-32BE -t UTF-8
上面使用printf
内置来强制十六进制代码点值为8个十六进制数字长,然后sed
将它们重写为4个十六进制常量,然后printf
再次将十六进制常量更改为八进制表示法,最后另一个printf
将八进制字符常量解释为四个 -可以iconv
作为big-endian UTF-32 输入的字节序列.(用printf
识别\x
转义码的方法会更简单,但Posix不需要它,dash
也不会实现它.)
只要为所有符号提供Unicode代码点(作为整数常量),您就可以使用不经修改的行来打印多个符号(示例执行dash
):
$ printf $(printf '\\%o' $(printf %08x 0x2388 0x266c 0xA | > sed 's/../0x& /g')) | > iconv -f UTF-32BE -t UTF-8 ?? $
注意:正如Geoff Nixon在评论中提到的那样,鱼壳(它无法接近Posix标准,并且据我所知,没有愿意遵守)会抱怨不带引号的%08x
格式参数printf
,因为它期望单词以%
成为职业生涯.因此,如果您使用fish,请在format参数中添加引号.