你如何回应Bash中的4位Unicode字符?

时间:2009-03-02 16:12:56

标签: bash shell unicode character-encoding

我想将Unicode骷髅和交叉骨添加到我的shell提示符中(特别是'SKULL AND CROSSBONES'(U + 2620)),但我无法弄清楚魔法咒语使回声吐出来,或者任何其他4位Unicode字符。两位数的一个很容易。例如,echo -e“\ x55”,。

除了下面的答案之外,应该注意的是,显然,您的终端需要支持Unicode,以使输出符合您的预期。 gnome-terminal做得很好,但默认情况下不一定开启。

在macOS的终端应用上转到首选项 - >编码并选择Unicode(UTF-8)。

18 个答案:

答案 0 :(得分:206)

在UTF-8中,它实际上是6位数(或3个字节)。

$ printf '\xE2\x98\xA0'
☠

要检查控制台如何编码,请使用hexdump:

$ printf ☠ | hexdump
0000000 98e2 00a0                              
0000003

答案 1 :(得分:82)

% echo -e '\u2620'     # \u takes four hexadecimal digits
☠
% echo -e '\U0001f602' # \U takes eight hexadecimal digits

这适用于Zsh(我已经检查过版本4.3)和Bash 4.2或更新版本。

答案 2 :(得分:65)

只要您的文本编辑器可以处理Unicode(可能以UTF-8编码),您就可以直接输入Unicode代码点。

例如,在Vim文本编辑器中,您将进入插入模式并按 Ctrl + V + U 和然后将代码点编号作为4位十六进制数字(必要时用零填充)。所以你要输入 Ctrl + V + U 2 6 2 0 。请参阅:What is the easiest way to insert Unicode characters into a document?

在运行Bash的终端上,你可以输入 CTRL + SHIFT + U 并输入你想要的字符的十六进制代码点。在输入过程中,光标应显示带下划线的u。您键入的第一个非数字结束输入,并呈现该字符。因此,您可以使用以下方法在Bash中打印U + 2620:

e c h o CTRL + SHIFT + û 2 6 2 0 输入 输入

(第一个输入结束Unicode输入,第二个输入运行echo命令。)

信用:Ask Ubuntu SE

答案 3 :(得分:31)

这是一个完全内部的Bash实现,没有分叉,无限大小的Unicode字符。

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

输出是:

─━│┃┄┅┆┇┈┉┊┋┌┍┎┏
┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟
┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯
┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿
╀╁╂╃╄╅╆╇╈╉╊╋╌╍╎╏
═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟
╠╡╢╣╤╥╦╧╨╩╪╫╬╭╮╯
╰╱╲╳╴╵╶╷╸╹╺╻╼╽╾╿
▀▁▂▃▄▅▆▇█▉▊▋▌▍▎▏
▐░▒▓▔▕▖▗▘▙▚▛▜▝▞▟
■□▢▣▤▥▦▧▨▩▪▫▬▭▮▯
▰▱▲△▴▵▶▷▸▹►▻▼▽▾▿
◀◁◂◃◄◅◆◇◈◉◊○◌◍◎●
◐◑◒◓◔◕◖◗◘◙◚◛◜◝◞◟
◠◡◢◣◤◥◦◧◨◩◪◫◬◭◮◯
◰◱◲◳◴◵◶◷◸◹◺◻◼◽◾◿

答案 4 :(得分:13)

只需在shell脚本中输入“☠”即可。在正确的语言环境和启用Unicode的控制台上,它将打印得很好:

$ echo ☠
☠
$

一个丑陋的“解决方法”是输出UTF-8序列,但这也取决于所使用的编码:

$ echo -e '\xE2\x98\xA0'
☠
$

答案 5 :(得分:12)

快速单行将UTF-8字符转换为3字节格式:

var="$(echo -n '☠' | od -An -tx1)"; printf '\\x%s' ${var^^}; echo

答案 6 :(得分:8)

我正在使用它:

$ echo -e '\u2620'
☠

这比搜索十六进制表示要容易得多......我在shell脚本中使用它。这适用于gnome-term和urxvt AFAIK。

答案 7 :(得分:7)

您可能需要将代码点编码为八进制,以便快速扩展以正确解码它。

以UTF-8编码的U + 2620是E2 98 A0。

所以在Bash,

export PS1="\342\230\240"

将使你的shell提示进入头骨和骨骼。

答案 8 :(得分:4)

这三个命令中的任何一个都会在控制台中打印出你想要的字符,只要控制台接受UTF-8个字符(大多数字符都是这样):

echo -e "SKULL AND CROSSBONES (U+2620) \U02620"
echo $'SKULL AND CROSSBONES (U+2620) \U02620'
printf "%b" "SKULL AND CROSSBONES (U+2620) \U02620\n"

SKULL AND CROSSBONES (U+2620) ☠

之后,您可以将实际字形(图像,字符)复制并粘贴到任何(启用UTF-8)文本编辑器。

如果你需要看看如何用UTF-8编码这样的Unicode代码点,请使用xxd(比od更好的十六进制查看器):

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

或者,在HEX中避免错误:0xE2 0x98 0xA0。即,空格(HEX 20)和换行(Hex 0A)之间的值。

如果您想深入了解将数字转换为字符:look here

答案 9 :(得分:4)

在bash中打印Unicode字符以输出use \ x,\ u或\ U(第一个用于2位十六进制,第二个用于4位十六进制,第三个用于任何长度)

echo -e '\U1f602'

我想将它分配给变量使用$&#39; ...&#39;语法

x=$'\U1f602'
echo $x

答案 10 :(得分:3)

printf内置(就像coreutils'printf)知道接受4位Unicode字符的\u转义序列:

   \uHHHH Unicode (ISO/IEC 10646) character with hex value HHHH (4 digits)

使用Bash 4.2.37(1)进行测试:

$ printf '\u2620\n'
☠

答案 11 :(得分:3)

如果你不介意Perl one-liner:

$ perl -CS -E 'say "\x{2620}"'
☠

-CS在输出上启用UTF-8解码,在输出上启用UTF-8编码。 -E将下一个参数评估为Perl,并启用了say等现代功能。如果您不想在最后添加换行符,请使用print代替say

答案 12 :(得分:3)

很抱歉恢复这个老问题。但是当使用bash时,有一种非常简单的方法可以从纯ASCII输入创建Unicode代码点,甚至根本不会分叉

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; };

按如下方式使用它来定义某些代码点

unicode crossbones 0x2620
echo "$crossbones"

或将第一个65536 unicode代码点转储到stdout(在我的机器上花费不到2秒。额外的空间是为了防止某些字符由于shell的等宽字体而相互流入):

for a in {0..65535}; do unicodes "$a"; printf ' '; done

或者讲一个非常典型的父母的故事(这需要Unicode 2010):

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别名varother,以便var的分配改变other。这里有一个有趣的部分是,var是本地命名空间的一部分,而other是全局命名空间的一部分。
    • 请注意,local中没有globalbash命名空间。变量保存在环境中,并且总是全局的。本地只是放弃当前值并在再次离开函数时恢复它。在具有local的函数内调用的其他函数仍会看到&#34; local&#34;值。这是一个与其他语言中的所有常规作用域规则完全不同的概念(bash的功能非常强大,但如果您是一名不了解其的程序员,则会导致错误。)

答案 13 :(得分:2)

使用Python2 / 3单线程很容易:

$ python -c 'print u"\u2620"'    # python2
$ python3 -c 'print(u"\u2620")'  # python3

结果:

答案 14 :(得分:2)

基于Stack Overflow问题 Unix cut, remove first token https://stackoverflow.com/a/15903654/781312

(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")

输出如下。

Octal representation is following \0342\0230\0240
☠

答案 15 :(得分:1)

在Bash中:

UnicodePointToUtf8()
{
    local x="$1"               # ok if '0x2620'
    x=${x/\\u/0x}              # '\u2620' -> '0x2620'
    x=${x/U+/0x}; x=${x/u+/0x} # 'U-2620' -> '0x2620'
    x=$((x)) # from hex to decimal
    local y=$x n=0
    [ $x -ge 0 ] || return 1
    while [ $y -gt 0 ]; do y=$((y>>1)); n=$((n+1)); done
    if [ $n -le 7 ]; then       # 7
        y=$x
    elif [ $n -le 11 ]; then    # 5+6
        y=" $(( ((x>> 6)&0x1F)+0xC0 )) \
            $(( (x&0x3F)+0x80 ))" 
    elif [ $n -le 16 ]; then    # 4+6+6
        y=" $(( ((x>>12)&0x0F)+0xE0 )) \
            $(( ((x>> 6)&0x3F)+0x80 )) \
            $(( (x&0x3F)+0x80 ))"
    else                        # 3+6+6+6
        y=" $(( ((x>>18)&0x07)+0xF0 )) \
            $(( ((x>>12)&0x3F)+0x80 )) \
            $(( ((x>> 6)&0x3F)+0x80 )) \
            $(( (x&0x3F)+0x80 ))"
    fi
    printf -v y '\\x%x' $y
    echo -n -e $y
}

# test
for (( i=0x2500; i<0x2600; i++ )); do
    UnicodePointToUtf8 $i
    [ "$(( i+1 & 0x1f ))" != 0 ] || echo ""
done
x='U+2620'
echo "$x -> $(UnicodePointToUtf8 $x)"

输出:

─━│┃┄┅┆┇┈┉┊┋┌┍┎┏┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟
┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿
╀╁╂╃╄╅╆╇╈╉╊╋╌╍╎╏═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟
╠╡╢╣╤╥╦╧╨╩╪╫╬╭╮╯╰╱╲╳╴╵╶╷╸╹╺╻╼╽╾╿
▀▁▂▃▄▅▆▇█▉▊▋▌▍▎▏▐░▒▓▔▕▖▗▘▙▚▛▜▝▞▟
■□▢▣▤▥▦▧▨▩▪▫▬▭▮▯▰▱▲△▴▵▶▷▸▹►▻▼▽▾▿
◀◁◂◃◄◅◆◇◈◉◊○◌◍◎●◐◑◒◓◔◕◖◗◘◙◚◛◜◝◞◟
◠◡◢◣◤◥◦◧◨◩◪◫◬◭◮◯◰◱◲◳◴◵◶◷◸◹◺◻◼◽◾◿
U+2620 -> ☠

答案 16 :(得分:0)

如果已知unicode字符的十六进制值

H="2620"
printf "%b" "\u$H"

如果知道unicode字符的十进制值

declare -i U=2*4096+6*256+2*16
printf -vH "%x" $U              # convert to hex
printf "%b" "\u$H"

答案 17 :(得分:0)

以下是所有可用的Unicode表情符号的列表:

https://en.wikipedia.org/wiki/Emoji#Unicode_blocks

示例:

echo -e "\U1F304"

要获取此字符的ASCII值,请使用hexdump

echo -e "" | hexdump -C

00000000  f0 9f 8c 84 0a                                    |.....|
00000005

然后使用十六进制格式的值

echo -e "\xF0\x9F\x8C\x84\x0A"