Bashで4桁のUnicode文字をどのようにエコーしますか?


224

シェルプロンプトにUnicodeの頭蓋骨とクロスボーン(具体的には 'SKULL AND CROSSBONES'(U + 2620))を追加したいのですが、それをエコーで吐き出す魔法の呪文などを理解できません。 4桁のUnicode文字。2桁のものは簡単です。たとえば、echo -e "\ x55"、。

以下の回答に加えて、出力が期待どおりになるためには、明らかに、端末がUnicodeをサポートしている必要があることに注意してください。gnome-terminalはこれをうまく行いますが、デフォルトで必ずしもオンになっているとは限りません。

macOSのターミナルアプリで、[設定]-> [エンコード]に移動し、[Unicode(UTF-8)]を選択します。


7
あなたのことを注意「2桁1つのは簡単(エコー)にある」コメントは最大値に対してのみ有効です "\x7F"(UTF-8ロケールでbashタグはあなたがあることを示唆している)...パターンによって表される単一のバイトが範囲内になることはありません\x80-\xFF。この範囲は、1バイトのUTF-8文字では無効です。たとえば、Unicode Codepointの値U+0080(つまり\x80)は実際にはUTF-8で2バイトです\xC2\x80。..
Peter.O

4
例えばprintf "\\u007C\\u001C"
kenorb

NB:で私のためにgnome-terminalecho -e '\ufc'でもUTF-8に文字エンコーディングを設定して、üを生成しません。ただし、たとえば期待どおりにurxvt印刷printf "\\ub07C\\ub01C"されます( またはボックスではありません)。
同型

@ Peter.Oなぜbashタグがこんなに役立つヒントなのですか?CJKまたは…で異なる端子は共通ですか?
同型

1
@ Peter.O zsh、fish、scsh、elvishなど...多くの異なるシェルがあり、それぞれが必要に応じて(またはそうでなく)Unicode文字を処理できます。「bash」は、この質問が、動作が異なる奇妙なシェルに関するものではないことを明確にします。
ますこみ2017

回答:


237

UTF-8では、実際には6桁(または3バイト)です。

$ printf '\xE2\x98\xA0'

コンソールでどのようにエンコードされているかを確認するには、hexdumpを使用します。

$ printf  | hexdump
0000000 98e2 00a0                              
0000003

5
鉱山は ではなく「 」を出力します...なぜですか?
trusktr 2012

8
それは本当だ。のLANG=C代わりに使用していたことがわかりましたLANG=en_US.UTF-8。これで、Gnomeの端末に記号が正しく表示されます...実際の端末(tty1-6)はまだ表示されません。
trusktr

6
16進ダンプを試みる人の場合:はに0000000 f0 9f 8d ba変換され\xf0\x9f\x8d\xbaます。エコーの例:echo -e "\xf0\x9f\x8d\xba"
ブレイズ

8
また、使用することができます$'...'使用せずに変数にしてエンコードされた文字を取得するための構文を$(...)自身がエスケープシーケンスを解釈しませんコンテキストで使用するため、捕獲サブシェルを:skull=$'\xE2\x98\xA0'
アンドリュー・ジャンキ

7
hexdumpについての別のこと:私のマシンでは、応答の2番目のコマンドが出力します0000000 98e2 00a0。もちろん、これ0000000は重要ではないオフセットですが\xe2\x98\xa0、マシンはリトルエンディアンのバイトオーダーを使用するため、それ以降のバイトはに変換されます。
sigalor 2016年

98
% echo -e '\u2620'     # \u takes four hexadecimal digits

% echo -e '\U0001f602' # \U takes eight hexadecimal digits
😂

これはZsh(バージョン4.3を確認しました)およびBash 4.2以降で動作します。


16
これを実行すると、\ u2620が出力されます。
ますこみ2009年

僕にも。ジュリアーノ、どちらのシェルを使っていますか?
Joachim Sauer、

2
申し訳ありませんが、zshを使用することを忘れていました。
ジュリアーノ

32
\ uのサポートはBash 4.2で追加されました。
Lri

4
私、Mac OS 10.14.2、bash(GNU bash、バージョン3.2.57(1)-release(x86_64-apple-darwin18))では機能しません。入力を出力するだけです-$ echo -e '\ u2620' <enter>が出力するだけです:\ u2620
Motti Shneor

68

テキストエディターがUnicode(おそらくUTF-8でエンコードされている)に対応できる限り、Unicodeコードポイントを直接入力できます。

たとえば、Vimテキストエディターでは、挿入モードに入り、Ctrl+ V+ Uを押してから、コードポイント番号を4桁の16進数(必要に応じてゼロで埋めます)として入力します。だから、次のように入力します。Ctrl+ V+ U 2 6 2 0。参照:Unicode文字をドキュメントに挿入する最も簡単な方法は何ですか?

バッシュを実行している端末で次のように入力します。CTRL+ SHIFT+ Uとしたい文字の16進コード・ポイントに入力します。入力中は、カーソルに下線が表示されますu。入力した最初の非数字は入力を終了し、文字をレンダリングします。したがって、次のようにしてB +でU + 2620を印刷することができます。

echo CTRL+ SHIFT+U2620ENTERENTER

(最初のエンターはUnicode入力を終了し、2番目のエンターはechoコマンドを実行します。)

クレジット:Ubuntu SEに質問する


1
hexademicalコードポイントのための良好な供給源であるunicodelookup.com/#0x2620/1
RobM

1
私が使用しているvimのバージョン(RHEL 6.3の7.2.411)は、ctrl-vとuの間にドットがあると希望どおりに応答しませんが、そのドットが省略されていると正常に動作します。
クリスジョンソン

@ChrisJohnson:私は指示からピリオドを削除しました、それはキーを押すことを意図したものではありませんでした(それがキーボード効果で表示されなかった理由です)。混乱させて申し訳ありません。
RobM 2013

5
注意:これは、Bashを実行している端末で、GnomeのようにGTK +環境で実行している場合にのみ機能します。
2014

1
能力は、C-S-u 2 6 2 0あなたの端末エミュレータ、X入力メソッド(XIM)、または同様の機能です。申し訳ありませんが、両方SHIFTCTRLターミナルレイヤーに送信することはできません。端末は、Xサーバーのようなキーシムやキーコードではなく、文字のみで話します(また、すべての意図と目的で7ビットです)。この世界では、CTRLマスクにつながる4つの最上位ビット(&0b00001111)
nabin-infoの

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

出力は:

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

私は、ラウンドアバウト方式の背後にある推論と、REPLY変数の具体的な使用法に非常に興味があります。私はあなたがbashソースを検査したり、実行したり、最適化するものを想定していると思います。これは、インタープリターに大きく依存しているにもかかわらず、選択がどのように最適化されるかを確認できます)。
nabin-info 2017

14

シェルスクリプトに「☠」を入力するだけです。正しいロケールとUnicode対応のコンソールでは、問題なく印刷されます。

$ echo 

$

醜い「回避策」は、UTF-8シーケンスを出力することですが、それは使用するエンコーディングにも依存します。

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

$

13

UTF-8文字を3バイト形式に変換するクイックワンライナー:

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

5
上記の例をすばやく呼び出さないでください(11個のコマンドとそのパラメーターを使用)...また、3バイトのUTF-8文字のみを処理します(UTF-8文字は1、2、または3バイトにすることができます)...これは少し短く、1-3 ++++バイトで動作します:printf "\\\x%s" $(printf '☠'|xxd -p -c1 -u).... xxdは 'vim-common'パッケージの一部として出荷されます
Peter.O

PS:上記のhexdump / awkの例がバイトペアのバイトシーケンスを切り替えていることに気づきました。これ UTF-8ダンプに適用されません。それがUTF-16LEのダンプでUnicodeコードポイントを出力したい場合、それは無害ですが、入力はUTF-8であり、出力は入力とまったく同じであるため(各16進数の前に\ xを加えたもの)、ここでは意味がありません。
-pair

7
UTF-8文字は1〜4バイトのシーケンスにすることができます
cms

1
Peter.O @のコメントに基づいて、私は、次のことを見つけるより大きく、かなり便利しばらく:hexFromGlyph(){ if [ "$1" == "-n" ]; then outputSeparator=' '; shift; else outputSeparator='\n'; fi for glyph in "$@"; do printf "\\\x%s" $(printf "$glyph"|xxd -p -c1 -u); echo -n -e "$outputSeparator"; done } # usage: $ hexFromGlyph ☠ ✿ \xE2\x98\xA0 \xE2\x9C\xBF $ hexFromGlyph -n ☠ ✿ \xE2\x98\xA0 \xE2\x9C\xBF
StephaneAG

2
いい神男。考えてみてください codepoints () { printf 'U+%04x\n' ${@/#/\'} ; } ; codepoints A R ☯ 🕉 z ... enjoyをお楽しみください
nabin-info

8

私はこれを使っています:

$ echo -e '\u2620'

これは、16進表記を検索するよりもかなり簡単です...私はこれをシェルスクリプトで使用しています。これはgnome-termとurxvt AFAIKで機能します。


2
@masukomi brewの使い方を知っている場合は、より新しいbashをインストールして使用できます。アップグレードされたbashを使用する場合、上記は私のMac端末で正常に動作します。
mcheema 2014年

はい、bashの新しいバージョンでは問題ありません。$ PS1はエコーエスケープフォーマットを使用しないなどのハウアープロンプト文字列
cms

6

プロンプトの拡張で正しくデコードするには、コードポイントを8進数としてエンコードする必要がある場合があります。

UTF-8としてエンコードされたU + 2620はE2 98 A0です。

バッシュでは

export PS1="\342\230\240"

シェルプロンプトを頭蓋骨と骨に表示します。


こんにちは、「e0 b6 85」に入力するコードは何ですか。どうすれば見つけられますか?
Udayantha Udy Warnasuriya 2013

16進数(基数16)の数値e0 b6 85を8進数(基数8)に変換するだけです。これを行うには、おそらく電卓を使用するのが最も簡単な方法です
cms

e0 b6 85 hexは340 266 205 octal
cms

これはうまくいきました、本当にありがとう!そしてところで、次のページで8進数バージョンを見つけることができます:graphemica.com/%E2%9B%B5
Perlnika

6

Unicode文字を出力するbashでは、\ x、\ uまたは\ Uを使用します(最初は2桁の16進数、2番目は4桁の16進数、3番目は任意の長さ)。

echo -e '\U1f602'

$ '...'構文を使用して変数に割り当てたい

x=$'\U1f602'
echo $x

5

Perlのワンライナーを気にしない場合:

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

-CS入力ではUTF-8デコードを、出力ではUTF-8エンコードを有効にします。-E次の引数をPerlとして評価し、say有効化などの最新の機能を使用します。最後に改行が不要な場合は、のprint代わりに使用してくださいsay


5

これらの3つのコマンドはいずれも、コンソールが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対応)テキストエディタに貼り付けます。

このようなUnicodeコードポイントがUTF-8でどのようにエンコードされているかを確認する必要がある場合は、xxd(odよりもはるかに優れた16進ビューア)を使用します。

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)とLine-Feed(Hex 0A)の間の値です。

数値を文字に変換する方法を詳しく知りたい場合は、ここを見て、BashでのASCIIエンコードに関するGregのwiki(BashFAQ)の記事をご覧ください。


再:「または、回避エラーにHEXで...」私はほとんどあなたが進文字で表現することをいくつかのバイナリエンコーディングにUnicodeの文字を変換すると、と思っていないのに役立ちます回避エラーを。"bash"でユニコード表記を使用すると、エラーを回避できます: "\ uHHHH ---値が---- 16進値HHHH(1から4桁の16進数)であるUnicode(ISO / IEC 10646)文字); \ UHHHHHHHH ----値が---- 16進値HHHHHHHH(1〜8桁の16進数)であるUnicode(ISO / IEC 10646)文字
Astara

4

printf(ただのcoreutils'などの組み込みはprintf)知っている\u4桁のUnicode文字を受け入れるエスケープシーケンスを:

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

Bash 4.2.37(1)でテストします。

$ printf '\u2620\n'

printfもシェルに組み込まれています。おそらく、デフォルトのmacOS bash(v3)を使用しています。\printfスタンドアロンの実行可能ファイルを使用するか、アップグレードされたbash
mcint

4

この古い質問を復活させてすみません。しかし、使用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秒未満です。追加のスペースは、シェルのモノスペースフォントが原因で特定の文字が互いに流れ込むのを防ぐためです):

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数値を16進数に変換して印刷し、これを別のprintf文字に渡されて、実際にUnicode文字を出力します
  • printf 8進数(0oct)、16進数(0xHEX)、10進数(0または1から9で始まる数値)を数値として認識します。そのため、最適な表現を選択できます。
  • printf -v var ..の出力をフォークせずにprintf変数に収集します(これ速度が大幅にします)。
  • local variable グローバル名前空間を汚染しないためにありますか
  • local -n var=otherエイリアスvarotherのように割り当て、var変更しますother。ここで興味深いのvarは、ローカルネームスペースの一部ですが、other一部であり、グローバル名前空間の一部です。
    • 以下のようなものはありませんので、予めご了承くださいlocalまたはglobal名前空間がbash。変数は環境に保持され、常にグローバルです。ローカルは、現在の値を単に格納し、関数が再び終了したときにそれを復元します。関数内から呼び出された他の関数は、local引き続き「ローカル」値を参照します。これは、他の言語にあるすべての通常のスコープルールとは根本的に異なる概念です(そして何をするかbashは非常に強力ですが、それを知らないプログラマーの場合はエラーにつながる可能性があります)。

まあ、私にはまったく機能しません。関数のいずれかを使用しようとすると、発行されます:6行目:ローカル:-n:無効なオプションローカル:使用法:ローカル名[=値] ...最新(10.14.2)MacOSおよびbash(GNU bashを使用しています) 、バージョン3.2.57(1)-release(x86_64-apple-darwin18))
Motti Shneor

4

利用可能なすべての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

そして、16進形式で通知された値を使用します

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

\ U <hex>文字列のエコーはOSXでは機能しません。引用符で囲まれたものを正確に出力するだけです。
masukomi


2

Python2 / 3ワンライナーで簡単:

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

結果:


2

バッシュで:

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

0

Unicode文字の16進値がわかっている場合

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

Unicode文字の10進値がわかっている場合

declare -i U=2*4096+6*256+2*16
printf -vH "%x" $U              # convert to hex
printf "%b" "\u$H"
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.