Bash'de ASCII karakterini farklı kod noktalarına göre nasıl yazdırabilirim?


12

ASCII tablosunda farklı sayı sistemlerinde kod noktaları olan 'J' karakteri vardır:

Oct   Dec   Hex   Char
112   74    4A    J

Bu karakteri printf '\112'veya tuşlarını kullanarak sekizlik bir kod noktasına basmak mümkündür echo $'\112'. Aynı karakteri ondalık ve onaltılık kod noktası sunumlarıyla nasıl yazdırabilirim?


Yanıtlar:


12

hex:

printf '\x4a'

Aralık:

printf "\\$(printf %o 74)"

Hex :-) için alternatif

xxd -r <<<'0 4a'

Neyse ki bu da çalışıyor awk.
Sridhar Sarnobat

7

Genel olarak, kabuk, aşağıdaki gibi tanımlanmış olmaları koşuluyla, değişkenlerdeki onaltılık, sekizlik ve ondalık sayıları anlayabilir integers:

$ declare -i v1 v2 v3 v4 v5 v6 v7
$ v1=0112
$ v2=74
$ v3=0x4a
$ v4=8#112
$ v5=10#74
$ v6=16#4a
$ v7=18#gg
echo "$v1 $v2 $v3 $v4 $v5 $v6 $v7"
74 74 74 74 74 74 304

Veya "Aritmetik Genişleme" nin sonucudur:

$ : $(( v1=0112, v2=74, v3=0x4a, v4=8#112, v5=10#74, v6=16#4a, v7=18#gg ))
$ echo "$v1 $v2 $v3 $v4 $v5 $v6 $v7"
74 74 74 74 74 74 304

Bu nedenle, değişken bir değere ait karakteri yazdırmanın tek bir yoluna ihtiyacınız vardır.
Ancak burada iki olası yol vardır:

$ var=$((0x65))
$ printf '%b\n' "\\$(printf '0%o' "$var")"
e

$ declare -i var
$ var=0x65; printf '%b\n' "\U$(printf '%08x' "$var")"
e

Biri değeri onaltılı bir dizeye dönüştürmek için iki printf, karakteri gerçekten yazdırmak için iki printf gereklidir.

İkincisi herhangi bir UNICODE noktasını basacaktır (konsolunuz doğru ayarlanmışsa).
Örneğin:

$ var=0x2603; printf '%b\n' "\U$(printf '%08x' "$var")"

Bir kar adam.

Bir UTF-8 gösterimi olan karakter olarak f0 9f 90 aeolup 0x1F42E. Ara cow face site:fileformat.infoiçin bunu elde :

$ var=0x1F42F; printf '%b\n' "\U$(printf '%08x' "$var")"
🐮

Not : UNICODE yolunda, 4.3'ten önceki bash (bu sürümde ve yukarı doğru) için UNICODE noktaları 128 ve 255 (ondalık olarak) arasındaki karakterler yanlış yazdırılabilir.


Referanslar

Dördüncü paragraf içi PARAMETERSyer man bash:

Değişkenin tamsayı öznitelik seti varsa, $ ((...)) genişletmesi kullanılmasa bile değer aritmetik bir ifade olarak değerlendirilir (aşağıdaki Aritmetik Genişleme'ye bakın).

İçindeki "ARİTMETİK DEĞERLENDİRME" içinde man bash:

Başında 0 olan sabitler sekizlik sayılar olarak yorumlanır. Baştaki 0x veya 0X onaltılık anlamına gelir. Aksi takdirde, sayılar [taban #] n biçimini alır; burada isteğe bağlı taban, aritmetik tabanı temsil eden 2 ile 64 arasında bir ondalık sayıdır ve n, bu tabandaki bir sayıdır. Taban # atlanırsa, taban 10 kullanılır. 9'dan büyük rakamlar, sırasıyla küçük harfler, @ ve _ büyük harfler ile temsil edilir. Taban 36'dan küçük veya ona eşitse, küçük ve büyük harfler 10 ile 35 arasındaki sayıları göstermek için birbirlerinin yerine kullanılabilir.


@ StéphaneChazelas Eh, bir kod noktası (her zaman) bir bayt değeri değildir. Bash (4.3'ten önceki sürümlerde) kod noktasının bayt değerini sağlar. Yani: karakter é(Octal: 351, Dec: 233, Hex: 0xE9) her zaman printf '\351'bayt değerini yazdırdığı için yanlış yazdırılır 0xE9. A, bir kodlama ile, terminal için ISO-8859-1çalışabilir (ve kuzenleri), ancak UTF-8 kodlanmış terminallerde, bir bayt değeri 0xE9olarak görünmelidir. devamı ....
Isaac

@ StéphaneChazelas Bir örnek için "bash 4.2 yanlış kodlar" ı ilk fark eden ve aradığım kişi değilim . Bash 4.3 ve üstü düzeltildi.
Isaac

TAMAM. Şimdi ne demek istediğini görüyorum (cevabının önceki sürümüne göre 4.3 ile test yapıyordum). Sadece bash-4.2, bash-4.1'in desteklemediğini \u(zsh'den geliyor) unutmayın.
Stéphane Chazelas



0

POSIX Awk stdlib kütüphanesini kullanabilirsiniz :

$ awklib 'BEGIN {print str_chr(74)}'
J

$ awklib 'BEGIN {print str_chr(+base_conv("4A", 16, 10))}'
J

$ awklib 'BEGIN {print str_chr(+base_conv(112, 8, 10))}'
J

$ awklib 'BEGIN {print str_chr(+base_conv(1001010, 2, 10))}'
J

0

Dönüştürülecek bir sayı listeniz varsa ve bir işlev çağrısından kaçınmak ve her karakter için bir alt kabuk oluşturmak istiyorsanız, ascii setini önceden tanımlayabilirsiniz:

ascii=$(for x in {0..9} {A..F}; do for y in {0..9} {A..F}; do echo -ne "\x$x$y"; done; done)

Boş karakterlerin hariç tutulduğunu unutmayın, bu nedenle her karakter 1 ile dengelenir.

Sonra böyle bir şey kullanın (satır başına 1 sayı olduğu varsayılır):

while read c; do out+="${ascii:$c-1:1}"; done <<< "$in"
echo "$out"

0

İşte tüm dönüşümleri kullanarak printf:

printf "%o" "'J" # 112 (oct)
printf "%d" "'J" # 74 (dec)
printf "%x" "'J" # 4a (hex)

printf '\112' # J (oct)
printf "\x$(printf %x 74)" # J (dec, requires double conversion)
printf '\x4a' # J (hex)
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.