Bash'de 4 basamaklı Unicode karakterini nasıl yankılanıyorsunuz?


224

Unicode kafatası ve kemiklerini kabuk istemime eklemek istiyorum (özellikle 'KAFATAS VE ÇAPRAZLAR' (U + 2620)), ama yankı tükürmek için sihirli büyüyü anlayamıyorum, ya da başka bir şey, 4 basamaklı Unicode karakter. İki basamaklı biri kolaydır. Örneğin, echo -e "\ x55",.

Aşağıdaki cevaplara ek olarak, çıktının beklediğiniz gibi olması için terminalinizin Unicode'u desteklemesi gerektiği açıktır. gnome-terminal bunun iyi bir iş çıkarır, ancak varsayılan olarak açık değildir.

MacOS'un Terminal uygulamasında Tercihler-> Kodlamalar bölümüne gidin ve Unicode'u (UTF-8) seçin.


7
Senin o Not "2 haneli kişinin (eko için) kolay" yorumunu değerlere kadar için geçerlidir "\x7F"(ki UTF-8 yerelinde bashetiketi sizindir anlaşılacağı) ... desenleri ile temsil tek bayt edilmektedir asla aralığında \x80-\xFF. Bu aralık, tek baytlık UTF-8 karakterlerinde yasadışıdır. örneğin, Unicode Kod Noktası değeri U+0080(yani. \x80) UTF-8'de aslında 2 bayttır .. \xC2\x80..
Peter.O

4
Örn printf "\\u007C\\u001C".
kenorb

Not: benim için gnome-terminal, echo -e '\ufc'UTF-8 olarak karakter kodlaması ayarlanmış olsa bile, bir ü üretmez. Ancak, örneğin urxvt, printf "\\ub07C\\ub01C"beklendiği gibi yazdırılır ( veya kutu ile değil).
izomorphismes

@ Peter.O Etiket neden bashbu kadar faydalı bir ipucu? CJK'da farklı terminaller mi yoksa…?
izomorphismes

1
@ Peter.O zsh, balık, scsh, elf, vb ... birçok farklı kabuk vardır, her biri istedikleri (veya değil) unicode karakterleri işleyebilir. "bash" bu sorunun farklı şeyler yapan bazı garip kabuklarla ilgili olmadığını açıkça ortaya koyuyor.
masukomi

Yanıtlar:


237

UTF-8'de aslında 6 basamak (veya 3 bayt).

$ printf '\xE2\x98\xA0'

Konsol tarafından nasıl kodlandığını kontrol etmek için hexdump kullanın:

$ printf  | hexdump
0000000 98e2 00a0                              
0000003

5
Maden çıktıları instead yerine " " ... Neden?
trusktr

8
Bu doğru. Bunun LANG=Cyerine kullandığımı keşfettim LANG=en_US.UTF-8. Şimdi Gnome'daki terminallerim sembolleri düzgün gösteriyor ... Gerçek terminaller (tty1-6) yine de yok.
trusktr

6
Bir hexdump deneyen insanlar için: 0000000 f0 9f 8d baçevirir \xf0\x9f\x8d\xba. Örnek yankı: echo -e "\xf0\x9f\x8d\xba".
Blaise

8
Ayrıca , kaçış dizilerini yorumlamayan bağlamlarda kullanılmak üzere, yakalama alt kabuğu $'...'kullanmadan kodlanmış karakteri bir değişkene almak için sözdizimini $(...)kullanabilirsiniz:skull=$'\xE2\x98\xA0'
Andrew Janke

7
Hexdump hakkında başka bir şey: makinemde, cevaptaki ikinci komut çıktı 0000000 98e2 00a0. Tabii ki bu 0000000sadece önemsiz bir ofset, ancak çevirildikten sonraki bayt \xe2\x98\xa0, çünkü makine küçük endian bayt sırasını kullanıyor.
sigalor

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

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

Bu Zsh (sürüm 4.3'ü kontrol ettim) ve Bash 4.2 veya daha yeni sürümlerde çalışır.


16
bunu yaptığımda tükürüyor.
masukomi

Benim için de. Hangi kabuğu kullanıyorsun, Juliano?
Joachim Sauer

2
Üzgünüm, zsh kullandığımı söylemeyi unuttum.
Juliano

32
Bash 4.2'de \ u desteği eklendi.
Lri

4
benim için çalışmıyor, Mac OS 10.14.2, bash (GNU bash, sürüm 3.2.57 (1) -çalışma (x86_64-apple-darwin18)). Yalnızca girdiyi yazdırır - $ echo -e '\ u2620' <enter> basitçe yazdırır: \ u2620
Motti Shneor

68

Metin editörleriniz Unicode (muhtemelen UTF-8'de kodlanmıştır) ile baş edebildiği sürece, Unicode kod noktasını doğrudan girebilirsiniz.

Örneğin, Vim metin düzenleyicide ekleme moduna girer ve Ctrl+ V+ tuşuna Uve ardından kod noktası numarasını 4 basamaklı onaltılık bir sayı olarak girersiniz (gerekirse sıfırlarla doldurun). Böylece Ctrl+ V+ yazarsınız U 2 6 2 0. Bkz: Belgeye Unicode karakterler eklemenin en kolay yolu nedir?

Bash çalıştıran bir terminalde CTRL+ SHIFT+ yazar Uve istediğiniz karakterin onaltılık kod noktasını yazarsınız. Giriş sırasında imlecinizin altı çizili olmalıdır u. Yazdığınız ilk basamak olmayan girdi girdiyi bitirir ve karakteri oluşturur. Böylece aşağıdakileri kullanarak B + 'da U + 2620 yazdırabilirsiniz:

echo CTRL+ SHIFT+U2620ENTERENTER

(İlk giriş Unicode girişini sonlandırır ve ikincisi echokomutu çalıştırır .)

Kredi bilgileri: Ask Ubuntu SE


1
Onaltılı kod noktaları için iyi bir kaynak unicodelookup.com/#0x2620/1
RobM

1
Kullandığım vim sürümü (RHEL 6.3 üzerinde 7.2.411) ctrl-v ve u arasında bir nokta olduğunda istenen şekilde yanıt vermez, ancak bu nokta atlandığında iyi çalışır.
Chris Johnson

@ChrisJohnson: Dönemi talimatlardan kaldırdım, tuşa basmak için tasarlanmamıştı (bu yüzden klavye efektiyle görünmedi). Karışıklık için özür dilerim.
RobM

5
Dikkat: Bu, Bash'i çalıştıran bir terminalde çalışır , ancak Gnome gibi GTK + ortamında çalıştırıyorsanız .
nr

1
Bu C-S-u 2 6 2 0, terminal öykünücünüzün, X Giriş Yöntemi'nin (XIM) veya benzerinin bir özelliğidir. AFAIK, her ikisini de SHIFTve CTRLterminal katmanına gönderemezsiniz . Terminal, X sunucunuz gibi keysyms ve keycode'lardan ziyade sadece karakterlerle konuşur (ayrıca, tüm amaçlar ve amaçlar için 7 bittir). Bu dünyada, CTRLen önemli 4 biti (& 0b00001111) maskeler, bu da sonuçlanır
nabin-info

31

İşte tamamen dahili bir Bash uygulaması, çatalsız, sınırsız boyutta Unicode karakter.

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

Çıktı şöyleydi:

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

Yuvarlama yönteminin ardındaki mantığı ve REPLY değişkeninin spesifik kullanımını merak ediyorum. Bash kaynağını denetlediğinizi veya optimizasyondan geçtiğinizi veya seçmenlerin son derece yorumlayıcı olmasına rağmen seçimlerinizin nasıl optimize edebileceğini görebildiğimi varsayıyorum).
nabin-info

14

Kabuk betiğinize "☠" yazmanız yeterlidir. Doğru yerel ayarda ve Unicode özellikli bir konsolda sorunsuz yazdırır:

$ echo 

$

Çirkin bir "geçici çözüm" UTF-8 dizisinin çıktısını almak olabilir, ancak bu aynı zamanda kullanılan kodlamaya da bağlıdır:

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

$

13

UTF-8 karakterlerini 3 baytlık biçime dönüştürmek için hızlı bir satırlık:

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

5
Yukarıdaki örneği hızlı çağırmazdım (11 komut ve parametreleri ile) ... Ayrıca sadece 3 bayt UTF-8 karakterlerini işler (UTF-8 karakterleri 1, 2 veya 3 bayt olabilir) ... Bu biraz daha kısa ve 1-3 ++++ için çalışmalar bayt: printf "\\\x%s" $(printf '☠'|xxd -p -c1 -u).... XXD 'vim-ortak' paketin parçası olarak sevk edilir
Peter.O

Not: Yukarıdaki hexdump / awk örneğinin bir bayt çiftindeki bayt dizisini döndürdüğünü fark ettim. Bu UTF-8 dökümü için geçerli değildir . UTF- 16LE'nin bir dökümü olsaydı ve Unicode Kod Noktaları çıktısı almak isterse , mantıklı olurdu , ancak giriş UTF-8 olduğu ve çıktı tam olarak girdi olarak (artı her onaltılık sayıdan önce \ x olduğu için) -pair)
Peter.O

7
UTF-8 karakterleri 1-4 baytlık diziler olabilir
cms

1
@ Peter.O yorumuna dayanarak, ben daha büyük, oldukça kullanışlı iken, aşağıdaki bulabilirsiniz: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
Tanrım dostum. codepoints () { printf 'U+%04x\n' ${@/#/\'} ; } ; codepoints A R ☯ 🕉 z Şunu düşünün: ... tadını çıkarın n
nabin-info

8

Bunu kullanıyorum:

$ echo -e '\u2620'

Bu, onaltılık bir temsili aramaktan çok daha kolay ... Bunu kabuk komut dosyalarında kullanıyorum. Gnome-term ve AFAIK urxvt üzerinde çalışır.


2
@masukomi demlemek nasıl kullanılacağını biliyorsanız daha yeni bir bash kurabilir ve kullanabilirsiniz. Yükseltilmiş bash kullanırken yukarıdaki mac terminalimde iyi çalışıyor.
mcheema

Evet, yeni bash sürümlerinde sorun yok. HOW istem dizeleri, örneğin $ PS1 yankı kaçış formatları kullanmaz
cms

6

Hızlı genişletmenin doğru kodunu çözebilmesi için kod noktasını sekizlik olarak kodlamanız gerekebilir.

UTF-8 olarak kodlanan U + 2620, E2 98 A0'dır.

Yani Bash’te,

export PS1="\342\230\240"

Kabuğunuzu kafatası ve kemiklere yönlendirir.


merhaba, "e0 b6 85" için girmem gereken kod nedir? nasıl bulabilirim?
Udayantha Udy Warnasuriya

sadece onaltılık (taban 16) sayıları e0 b6 85'i sekizlik (taban 8) haline dönüştürün - bir hesap makinesi kullanmak muhtemelen bunu yapmanın en kolay yoludur
cms

e0 b6 85 altıgen 340266205 sekizli
cms

Bu işe yaradı, çok teşekkürler! Ve btw yapabilirsiniz findal bu sayfalara sekizlik sürümü: graphemica.com/%E2%9B%B5
Perlnika

6

Bash'da çıktı almak üzere bir Unicode karakter yazdırmak için \ x, \ u veya \ U kullanın (önce 2 basamaklı onaltılık için ikinci, 4 basamaklı onaltılık için ikinci, herhangi bir uzunluk için üçüncü)

echo -e '\U1f602'

Bir değişkene atamak istiyorum $ '...' sözdizimini kullan

x=$'\U1f602'
echo $x

5

Bir Perl tek astarını sakıncası yoksa:

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

-CSgirişte UTF-8 kod çözme ve çıkışta UTF-8 kodlamayı etkinleştirir. -Ebir sonraki argümanı sayetkin gibi modern özelliklerle Perl olarak değerlendirir . Sonunda bir satırsonu istemiyorsanız, printyerine kullanın say.


5

Bu üç komuttan herhangi biri, konsolun UTF-8 karakterlerini kabul etmesi şartıyla, bir konsolda istediğiniz karakteri yazdıracaktır (en güncel olanlar yapar):

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) 

Ardından, gerçek glifi (resim, karakter) kopyalayıp herhangi bir (UTF-8 etkin) metin düzenleyicisine yapıştırabilirsiniz.

Böyle Unicode Kod Noktasının UTF-8'de nasıl kodlandığını görmeniz gerekiyorsa, xxd (od'dan çok daha iyi onaltılık görüntüleyici) kullanın:

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

Veya hataları önlemek için HEX'te: 0xE2 0x98 0xA0. Yani, boşluk (HEX 20) ve Satır Besleme (Hex 0A) arasındaki değerler.

Sayıları karakterlere dönüştürmek için derin bir dalış yapmak istiyorsanız: Greg'in wiki'sinden (BashFAQ) Bash'te ASCII kodlaması hakkında bir makale görmek için buraya bakın!


re: "Veya, HEX hatalardan kaçınmak için ..." Bir unicode char dönüştürmek onaltılık chars ifade bazı ikili kodlama, hatalar önlemek yardımcı olduğunu düşünüyorum . "Bash" içindeki unicode gösterimini kullanmak hataları daha iyi önleyecektir, örneğin: "\ uHHHH --- değeri ---- onaltılık değer HHHH (bir ila dört onaltılık basamak) olan Unicode (ISO / IEC 10646) karakteri; \ UHHHHHHHH ---- değeri ---- onaltılık değer HHHHHHHH (bir ila sekiz onaltılık basamak) olan Unicode (ISO / IEC 10646) karakteri
Astara

4

printfYerleşiği (sadece coreutils' olarak printf) bilir \u4 basamaklı Unicode karakterleri kabul çıkış sırası:

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

Bash 4.2.37 (1) ile test edin:

$ printf '\u2620\n'

printf ayrıca yerleşik bir kabuktur. Muhtemelen varsayılan macOS bash (v3) kullanıyorsunuz. İle deneyin \printfbağımsız çalıştırılabilir kullanabilir veya yükseltilmiş bash ile denemek için
mcint

4

Bu eski soruyu dirilttiğim için üzgünüm. Ancak kullanırken bash, düz ASCII girişinden Unicode kod noktaları oluşturmak için çok kolay bir yaklaşım vardır, bu da hiç çatallanmaz :

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

Belirli kod noktalarını tanımlamak için aşağıdaki gibi kullanın

unicode crossbones 0x2620
echo "$crossbones"

veya ilk 65536 unicode kod noktasını stdout'a dökmek için (makinemde 2 saniyeden az sürer. Ek alan, kabuğun tek aralıklı yazı tipi nedeniyle belirli karakterlerin birbirine akmasını önlemektir):

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

ya da biraz çok tipik bir ebeveynin hikayesini anlatmak için (bunun Unicode 2010'a ihtiyacı var):

unicodes 0x1F6BC 32 43 32 0x1F62D 32 32 43 32 0x1F37C 32 61 32 0x263A 32 32 43 32 0x1F4A9 10

Açıklama:

  • printf '\UXXXXXXXX' herhangi bir Unicode karakterini yazdırır
  • printf '\\U%08x' number\UXXXXXXXXsayı Hex'e dönüştürülmüş olarak yazdırılır , bu daha sonra printfUnicode karakterini yazdırmak için diğerine beslenir
  • printf sekizlik (0oct), onaltılık (0xHEX) ve ondalık (0 veya 1 ile 9 ile başlayan sayılar) sayı olarak tanır, böylece hangi gösterimin en uygun olduğunu seçebilirsiniz
  • printf -v var ..çıktısını toplar printfbir değişken içine, çatal olmadan (müthiş şeyler hızlandırır)
  • local variable küresel isim alanını kirletmeyecek mi
  • local -n var=otherdiğer adlar variçinother hiç öyle ki atama, varkişiliklerinden other. Burada ilginç bir kısım var, yerel ad otheralanının bir parçası iken , küresel ad alanının bir parçası.
    • Lütfen ad localveya globalad alanı diye bir şey olmadığını unutmayın bash. Değişkenler çevrede tutulur ve bunlar her zaman küreseldir. Yerel, geçerli değeri kaldırır ve işlev tekrar bırakıldığında geri yükler. İle işlevin içinden çağrılan diğer işlevler localyine de "yerel" değeri görür. Bu, diğer dillerde bulunan normal kapsam belirleme kurallarından tamamen farklı bir kavramdır (ve bashçok güçlü olan, ancak bunun farkında olmayan bir programcıysanız hatalara neden olabilir).

iyi - benim için hiç çalışmıyor. işlevlerinizden herhangi birini kullanma girişimi, yayar: satır 6: yerel: -n: geçersiz seçenek yerel: kullanım: yerel ad [= değer] ... En son (10.14.2) MacOS ve bash (GNU bash) kullanıyorum , sürüm 3.2.57 (1) -çalışma (x86_64-apple-darwin18))
Motti Shneor

4

İşte tüm unicode emoji'lerin listesi:

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

Misal:

echo -e "\U1F304"
🌄

Bu karakterin ASCII değerini almak için hexdump kullanın

echo -e "🌄" | hexdump -C

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

Ve onaltılık formatta bildirilen değerleri kullanın

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

\ U <hex> dizesinin yankılanması OSX üzerinde çalışmaz, tırnak işaretleri içinde tam olarak çıktı alır.
masukomi


2

Python2 / 3 tek astarlı kolay:

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

Sonuçlar:


2

Bash'ta:

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

Çıktı:

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

0

Unicode karakterinin onaltılık değeri biliniyorsa

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

Unicode karakterin ondalık değeri biliniyorsa

declare -i U=2*4096+6*256+2*16
printf -vH "%x" $U              # convert to hex
printf "%b" "\u$H"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.