How do you echo a 4-digit Unicode character in Bash?
我想把unicode骷髅和交叉骨骼添加到shell提示(特别是"骷髅和交叉骨骼"(U+2620)),但我无法找到让echo吐出来的魔法咒语,或任何其他4位unicode字符。两位数很容易。例如,echo-e"x55",。
除了下面的答案外,还应该注意到,显然,您的终端需要支持Unicode,以便输出符合您的期望。gnome终端可以很好地完成这项工作,但默认情况下不一定要打开它。
在MacOS的终端应用程序上,进入Preferences->Encodings并选择Unicode(UTF-8)。
在UTF-8中,它实际上是6位数(或3字节)。
1 2 | $ printf '\xE2\x98\xA0' ? |
要检查控制台如何对其进行编码,请使用hexdump:
1 2 3 | $ printf ? | hexdump 0000000 98e2 00a0 0000003 |
4
这在zsh(我检查过4.3版)和bash 4.2或更新版本中都有效。
只要文本编辑器能够处理Unicode(大概是用UTF-8编码的),就可以直接输入Unicode码位。
例如,在VIM文本编辑器中,您将进入插入模式,然后按ctrl+v+u,然后按代码点号作为4位十六进制数(如有必要,请用零填充)。因此,您可以键入ctrl+vbkbbd+u 2 6 2 0。请参见:将Unicode字符插入文档的最简单方法是什么?
在运行bash的终端上,您可以键入ctrl+shift+u,并键入所需字符的十六进制代码点。在输入期间,光标应显示带下划线的
AKBDCBDCCtrL+SHIFT+UKBD62XEnterXEnter
(第一个回车结束Unicode输入,第二个回车运行
学分:询问Ubuntu SE
这里是一个完全内部的bash实现,没有分叉,Unicode字符的大小不受限制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | fast_chr() { local __octal local __char printf -v __octal '%03o' $1 printf -v __char \\$__octal REPLY=$__char } function unichr { local c=$1 # Ordinal of char local l=0 # Byte ctr local o=63 # Ceiling local p=128 # Accum. bits local s='' # Output string (( c < 0x80 )) && { fast_chr"$c"; echo -n"$REPLY"; return; } while (( c > o )); do fast_chr $(( t = 0x80 | c & 0x3f )) s="$REPLY$s" (( c >>= 6, l++, p += o+1, o>>=1 )) done fast_chr $(( t = p | c )) echo -n"$REPLY$s" } ## test harness for (( i=0x2500; i<0x2600; i++ )); do unichr $i done |
产量为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ─━│┃┄┅┆┇┈┉┊┋┌┍┎┏ ┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟ ┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯ ┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿ ╀╁╂╃╄╅╆╇╈╉╊╋???? ═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟ ╠╡╢╣╤╥╦╧╨╩╪╫╬╭╮╯ ╰╱╲╳???????????? ?▁▂▃▄▅▆▇█▉▊▋▍▎▏ ???▓▔▕?????????? □?????????????? ??▲△????????▼▽?? ??????◆◇???○??◎● ???????????????? ??◢◣◤◥?????????? ???????????????? |
只放"?"在shell脚本中。在正确的区域设置和启用Unicode的控制台上,它的打印效果很好:
1 2 3 | $ echo ? ? $ |
一个丑陋的"解决方法"是输出UTF-8序列,但这也取决于所使用的编码:
1 2 3 | $ echo -e '\xE2\x98\xA0' ? $ |
快速一行程序将utf-8字符转换为3字节格式:
1 | var="$(echo -n '?' | od -An -tx1)"; printf '\\x%s' ${var^^}; echo |
我用这个:
1 2 | $ echo -e '\u2620' ? |
这比搜索十六进制表示更容易…我在shell脚本中使用这个。它适用于gnome术语和urxvt-afaik。
您可能需要将代码点编码为八进制,以便提示扩展以正确解码它。
U+2620编码为UTF-8是e2 98 a0。
所以在狂欢中,
1 | export PS1="\342\230\240" |
会使你的外壳迅速进入头骨和骨头。
这三个命令中的任何一个都将在控制台中打印所需的字符,前提是控制台确实接受UTF-8字符(大多数当前的命令都接受):
1 2 3 4 5 6 | echo -e"SKULL AND CROSSBONES (U+2620) \U02620" echo $'SKULL AND CROSSBONES (U+2620) \U02620' printf"%b""SKULL AND CROSSBONES (U+2620) \U02620 " SKULL AND CROSSBONES (U+2620) ? |
之后,您可以将实际的字形(图像、字符)复制并粘贴到任何(启用了UTF-8)文本编辑器中。
如果您需要了解这样的Unicode代码点是如何用UTF-8编码的,请使用XXD(比OD更好的十六进制查看器):
1 2 3 4 | echo $'(U+2620) \U02620' | xxd 0000000: 2855 2b32 3632 3029 20e2 98a0 0a (U+2620) .... That means that the UTF8 encoding is: e2 98 a0 |
或者,以十六进制表示以避免错误:0xe2 0x98 0xa0。也就是说,空格(hex 20)和换行(hex 0a)之间的值。
如果你想深入研究把数字转换成字符:看这里!
在bash中,要打印要输出的Unicode字符,请使用x、u或u(第一个用于2位十六进制,第二个用于4位十六进制,第三个用于任何长度)
4我想将它赋给一个变量,使用$...'语法
1 2 | x=$'\U1f602' echo $x |
1 | \uHHHH Unicode (ISO/IEC 10646) character with hex value HHHH (4 digits) |
使用bash 4.2.37(1)进行测试:
1 2 3 | $ printf '\u2620 ' ? |
如果您不介意使用perl-one行程序:
16很抱歉又提了这个老问题。但是,在使用
1 2 | unicode() { local -n a="$1"; local c; printf -vc '\\U%08x'"$2"; printf -va"$c"; } unicodes() { local a c; for a; do printf -vc '\\U%08x'"$a"; printf"$c"; done; }; |
按如下方式定义某些代码点
1 2 | unicode crossbones 0x2620 echo"$crossbones" |
或者将前65536个Unicode代码转储到stdout(在我的计算机上不到2秒)。额外的空间是为了防止某些字符由于shell的单空间字体而相互流入):
1 | for a in {0..65535}; do unicodes"$a"; printf ' '; done |
或者说一些非常典型的家长故事(这需要Unicode 2010):
1 | unicodes 0x1F6BC 32 43 32 0x1F62D 32 32 43 32 0x1F37C 32 61 32 0x263A 32 32 43 32 0x1F4A9 10 |
说明:
printf '\UXXXXXXXX' 打印出任何Unicode字符printf '\\U%08x' number 打印\UXXXXXXXX 并将数字转换为十六进制,然后送入另一个printf 以实际打印出unicode字符。printf 将八进制(0oct)、十六进制(0xhex)和十进制(0或以1到9开头的数字)识别为数字,因此您可以选择最适合的表示形式。printf -v var .. 把printf 的输出集合成一个变量,不需要叉子(可以极大地加快速度)。local variable 的存在不会污染全局命名空间local -n var=other 将var 化名为other ,这样对var 的赋值就改变了other 。其中一个有趣的部分是,var 是本地命名空间的一部分,而other 是全局命名空间的一部分。- 请注意,
bash 中没有local 或global 名称空间。变量保存在环境中,并且始终是全局的。local只会将当前值放在一边,并在函数再次离开时将其恢复。从带有local 的函数中调用的其他函数仍将看到"本地"值。这是一个与其他语言中的所有正常范围规则根本不同的概念(而且,bash 所做的功能非常强大,但如果您是一个不知道这一点的程序员,则可能会导致错误)。
- 请注意,
使用python2/3一个内衬很容易:
1 2 | $ python -c 'print u"\u2620"' # python2 $ python3 -c 'print(u"\u2620")' # python3 |
结果:
1 | ? |
根据堆栈溢出问题unix cut,删除第一个令牌和https://stack overflow.com/a/15903654/781312:
1 2 3 | (octal=$(echo -n ? | od -t o1 | head -1 | cut -d' ' -f2- | sed -e 's#\([0-9]\+\) *#\\0\1#g') echo Octal representation is following $octal echo -e"$octal") |
输出如下。
1 2 | Octal representation is following \0342\0230\0240 ? |
以下是所有可用的Unicode emoji的列表:
https://en.wikipedia.org/wiki/emoji unicode_块
例子:
1 2 | echo -e"\U1F304" ?? |
要获取此字符的ASCII值,请使用hexdump
1 2 3 4 | echo -e"??" | hexdump -C 00000000 f0 9f 8c 84 0a |.....| 00000005 |
然后使用十六进制格式通知的值
1 2 | echo -e"\xF0\x9F\x8C\x84\x0A" ?? |
如果已知Unicode字符的十六进制值
1 2 | H="2620" printf"%b""\u$H" |
如果已知Unicode字符的十进制值
1 2 3 | declare -i U=2*4096+6*256+2*16 printf -vH"%x" $U # convert to hex printf"%b""\u$H" |