Alfabe için ASCII değerleri almak için Bash betiği


Yanıtlar:


70

Bu iki işlevi tanımlayın (genellikle diğer dillerde bulunur):

chr() {
  [ "$1" -lt 256 ] || return 1
  printf "\\$(printf '%03o' "$1")"
}

ord() {
  LC_CTYPE=C printf '%d' "'$1"
}

Kullanımı:

chr 65
A

ord A
65

7
@ dmsk80: +1. Onlar bir yazım hatası nokta düşünüyorum benim gibi Diğerleri için: "'A"Eğer kullanırsanız oysa doğru olduğunu "A"söylemek olacaktır: A: invalid number. Printf tarafında yapıldığı görülüyor (yani, kabuğunda, "'A"aslında 2 karakter, a 've a A. Bunlar printf'e geçirildi. Ve printf bağlamında, A'nın ascii değerine dönüştürülür (ve sonunda yazdırılır). Ondalık olarak '%d'. 'Ox%x'Heksa cinsinden göstermek ya da '0%o'sekizli yapmak için kullanın))
Olivier Dulac

3
-1 o şaka ... nasıl çalıştığını açıklayan değil: D, ama ciddi bu ne printf "\\$(printf '%03o' "$1")", '%03o', LC_CTYPE=Cve de tek tırnak "'$1"do?
razzak

1
Tüm ayrıntıları SSS 71'de okuyun . Mükemmel bir ayrıntılı analiz.

19

Setin tamamını aşağıdakiler ile görebilirsiniz:

$ man ascii

Sekizli, onaltılı ve ondalık tabloları alırsınız.


Debian merkezli dağıtımlar için bir ascii paketi de var, ancak (en azından şimdi) soru bash olarak etiketlendi, bu yüzden bunlar OP'ye yardımcı olmaz. Aslında, sistemime yüklendi ve benim ascii'den tek aldığım şey onun erkek sayfası.
Joe,

12

UTF-8 karakterlerine genişletmek istiyorsanız:

$ perl -CA -le 'print ord shift' 😈
128520

$ perl -CS -le 'print chr shift' 128520
😈

İle bash, kshveya zshbuiltins:

$ printf "\U$(printf %08x 128520)\n"
😈

Bir kare kutu karakteri koymak niyetinde miydiniz, yoksa orijinal karakter postada gösterilmez ve yerine kare kutu karakteri kullanılır.
mtk

1
@mtk, UTF-8'i görüntüleyen bir tarayıcıya ve bu 128520 karakterine sahip bir fonta ihtiyacınız var .
Stéphane Chazelas

Son Chrome'dayım ve UTF-8'i desteklemediğini sanmıyorum. Hangi tarayıcıda olduğunuzu bilmek ister misiniz?
mtk

@mtk, iceweaselon Debian sid. İceweasel'in web konsolu tarafından teyit edilen yazı tipi "DejaVu Sans" dır ve Debian'dan dejavu-fonts.org adresinden gelen ttf-dejavu ttf-dejavu-çekirdekli ttf-dejavu-ekstra paketleri kurdum
Stéphane Chazelas

128520'nin tabanı nedir? Kendi ctbl()düzgün görüntülemek için, ve bir dizenin başından kömürü dilim beni sağlayacak gibi görünüyor printf, ama o koyar 4*((o1=360)>=(d1=240)|(o2=237)>=(d2=159)|(o3=230)>=(d3=152)|(o4=210)>=(d4=136))içinde $OPTARGbayt değerleri için.
mikeserv

12

Bu iyi çalışıyor

echo "A" | tr -d "\n" | od -An -t uC

echo "A"                              ### Emit a character.
         | tr -d "\n"                 ### Remove the "newline" character.
                      | od -An -t uC  ### Use od (octal dump) to print:
                                      ### -An  means Address none
                                      ### -t  select a type
                                      ###  u  type is unsigned decimal.
                                      ###  C  of size (one) char.

tam olarak eşdeğer:

echo -n "A" | od -An -tuC        ### Not all shells honor the '-n'.

3
Küçük bir açıklama ekleyebilir misiniz?
Bernhard

girişden "\ n" (yeni satır) kaldırmak için tr. od -t için kullanılır. dC ondalık karakterde yazdırmak içindir.
Saravanan

1
echo -nİhtiyacı ortadan kaldıran sondaki newline'ı bastırıyortr -d "\n"
Gowtham

2
@ Gowtham, echoörneğin Unix uyumlu ekolarda değil, sadece bazı uygulamalarda . printf %s Ataşınabilir olanı olurdu.
Stéphane Chazelas 27:13

6

Basit (ve şık?) Bash çözümüne gidiyorum:

for i in {a..z}; do echo $(printf "%s %d" "$i" "'$i"); done

Bir komut dosyasında aşağıdakileri kullanabilirsiniz:

CharValue="A"
AscValue=`printf "%d" "'$CharValue"

CharValue'dan önceki tek alıntıya dikkat edin. Zorunlu ...


1
Cevabınız dsmsk80'in cevabından farklı mı?
Bernhard

1
Bu soruya ilişkin yorumum "alfabenin değerleri için ASCII değerlerinin nasıl elde edileceği" dir. Bir karakter için ASCII değerini alma fonksiyonunun nasıl tanımlanacağı değil. Bu yüzden ilk cevabım, alfabenin ASCII değerlerini elde etmek için tek satırlık kısa bir komut.
phulstaert

Ben senin fikrini anlıyorum ama hala her iki cevabın alt satırında olduğunu düşünüyorum printf "%d".
Bernhard

2
Bunun sonuca ulaşmak için sürecin çok önemli bir parçası olduğuna katılıyorum, ancak xmpirate'ın “benim için” ve bir dizi kullanımı hakkında bildiği varsayımını yapmak istemedim. Eğer bir liste istiyorsa, bu gerçek bir zaman kazandıran ;-) olabilir. Ayrıca gelecekteki okuyucular eklemelerimi faydalı bulabilir.
phulstaert

6
ctbl()  for O                   in      0 1 2 3
        do  for o               in      0 1 2 3 4 5 6 7
                do for  _o      in      7 6 5 4 3 2 1 0
                        do      case    $((_o=(_o+=O*100+o*10)?_o:200)) in
                                (*00|*77) set   "${1:+ \"}\\$_o${1:-\"}";;
                                (140|42)  set   '\\'"\\$_o$1"           ;;
                                (*)       set   "\\$_o$1"               ;esac
                        done;   printf   "$1";   shift
                done
        done
eval '
ctbl(){
        ${1:+":"}       return "$((OPTARG=0))"
        set     "" ""   "${1%"${1#?}"}"
        for     c in    ${a+"a=$a"} ${b+"b=$b"} ${c+"c=$c"}\
                        ${LC_ALL+"LC_ALL=$LC_ALL"}
        do      while   case  $c in     (*\'\''*) ;; (*) ! \
                                 set "" "${c%%=*}='\''${c#*=}$1'\'' $2" "$3"
                        esac;do  set    "'"'\''\${c##*\'}"'$@";  c=${c%\'\''*}
        done;   done;   LC_ALL=C a=$3 c=;set "" "$2 OPTARG='\''${#a}*("
        while   [ 0 -ne "${#a}" ]
        do      case $a in      ([[:print:][:cntrl:]]*)
                        case    $a in   (['"$(printf \\1-\\77)"']*)
                                        b=0;;   (*)     b=1
                        esac;;  (['"$(  printf  \\200-\\277)"']*)
                                        b=2;;   (*)     b=3
                esac;    set    '"$(ctbl)"'     "$@"
                eval "   set    \"\${$((b+1))%"'\''"${a%"${a#?}"}"*}" "$6"'\''
                a=${a#?};set    "$((b=b*100+${#1}+${#1}/8*2)))" \
                                "$2(o$((c+=1))=$b)>=(d$c=$((0$b)))|"
        done;   eval "   unset   LC_ALL  a b c;${2%?})'\''"
        return  "$((${OPTARG%%\**}-1))"
}'

İlk ctbl()- en üstte - sadece bir kez çalışıyor. ( sed -n lYazdırılabilirlik adına filtrelenmiş olan) aşağıdaki çıktıyı üretir :

ctbl | sed -n l

 "\200\001\002\003\004\005\006\a\b\t$
\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\
\035\036\037 !\\"#$%&'()*+,-./0123456789:;<=>?" "@ABCDEFGHIJKLMNOPQRS\
TUVWXYZ[\\]^_\\`abcdefghijklmnopqrstuvwxyz{|}~\177" "\200\201\202\203\
\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\
\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\
\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\
\267\270\271\272\273\274\275\276\277" "\300\301\302\303\304\305\306\
\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\
\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\
\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\
\372\373\374\375\376\377"$

... hepsi 8-bit bayt (daha az NUL) , 64-byte sınırlarında eşit şekilde bölünmüş dört kabuk-alıntı dizeye bölünmüştür. Şeritler sekizlik aralıkları gibi temsil edilebilir \200\1-\77, \100-\177, \200-\277, \300-\377, bayt 128 için bir yer tutucu olarak kullanıldığı NUL.

İlk ctbl()'varlığı için tüm amacı böylece bu dizeleri oluşturmak için s evalikinci tanımlayabilir ctbl()bunları anlamıyla sonra gömülü fonksiyonu. Bu şekilde, her ihtiyaç duyulduğunda tekrar üretmeye gerek kalmadan fonksiyonda referans alınabilir. evalİkinci ctbl()işlevi ne zaman tanımladığınızda ilk olmak sona erecektir.

İkinci ctbl()işlevin üst yarısı çoğunlukla burada yardımcıdır - çağrıldığında etkileyebileceği herhangi bir mevcut kabuk durumunu taşınabilir ve güvenli bir şekilde seri hale getirmek için tasarlanmıştır. Üst döngü, kullanmak isteyebileceği herhangi bir değişkenin değerindeki herhangi bir teklifi verir ve ardından tüm sonuçları konumsal parametrelerinde istifler.

İlk iki satır, ilk önce hemen 0 döndürür ve $OPTARGişlevin ilk argümanı en az bir karakter içermiyorsa aynı olarak ayarlanır . Ve eğer öyleyse, ikinci satır derhal ilk argümanını sadece ilk karakterine keser - çünkü fonksiyon bir anda sadece bir karakter kullanır. Önemli olarak, mevcut yerel bağlamda bunu yapar; bu, bir karakterin tek bir bayttan daha fazlasını içermesi durumunda, kabuğun çok baytlık karakterleri düzgün bir şekilde desteklemesi koşuluyla, karakterde olmayanlar dışında herhangi bir baytı atmayacağı anlamına gelir. ilk argümanının ilk karakteri.

        ${1:+":"}       return "$((OPTARG=0))"
        set     "" ""   "${1%"${1#?}"}"

Daha sonra eğer gerekliyse kaydetme döngüsünü yapar ve daha sonra LC_ALLdeğişkene atayarak mevcut yerel ayar içeriğini her kategori için C yerel ayarına yeniden tanımlar . Bu noktadan itibaren, bir karakter yalnızca tek bir bayttan oluşabilir ve bu nedenle, ilk argümanının ilk karakterinde birden fazla bayt varsa, bunların her biri kendi başlarına ayrı ayrı karakterler olarak adreslenebilir olmalıdır.

        LC_ALL=C

Bu sebepten dolayı, fonksiyonun ikinci yarısı, tek bir koşu sırasının aksine bir while döngüdür . Kabuk hangi Çoğu durumda muhtemelen, çağrı başına yalnızca bir kez çalıştırmak, ancak ctbl()çok bayt karakterler kolları düzgün tanımlanır o olabilir döngü.

        while   [ 0 -ne "${#a}" ]
        do      case $a in      ([[:print:][:cntrl:]]*)
                        case    $a in   (['"$(printf \\1-\\77)"']*)
                                        b=0;;   (*)     b=1
                        esac;;  (['"$(  printf  \\200-\\277)"']*)
                                        b=2;;   (*)     b=3
                esac;    set    '"$(ctbl)"'     "$@"

Yukarıdaki $(ctbl)komut ikame işleminin yalnızca bir kez - evalfonksiyon ilk tanımlandığında - değerlendirildiğine ve sonsuza dek belirtecin kabuğun belleğine kaydedildiği şekilde bu komut ikamesinin değişmez çıktısıyla değiştirildiğine dikkat edin. Aynısı iki casekomut komutu yerine geçmesi için de geçerlidir . Bu fonksiyon hiç bir alt kabuk veya başka bir komut çağırmaz. Ayrıca, giriş / çıkış okuma veya yazma girişiminde bulunmayacaktır (bazı hata teşhis mesajları hariç - muhtemelen bir hatayı gösterir) .

Ayrıca, döngü sürekliliği testinin basit olmadığını [ -n "$a" ], çünkü hayal kırıklığımı bulduğum gibi, bir nedenden dolayı bir bashkabuğun yaptığı:

char=$(printf \\1)
[ -n "$char" ] || echo but it\'s not null\!

but it's not null!

... ve böylece $aher bir yinelemede açıkça farklı şekilde davranan ( yinelenen ) doğru bir şekilde len sayısını 0 ile karşılaştırıyorum .

caseÇekler dört dizeleri ve mağazalarda byte'ın sete bir referans herhangi eklenmek üzere ilk bayt $b. Daha sonra kabuğun ilk dört konumsal parametresi selefinin gömdüğü ve yazdığı setdizgilerdir .evalctbl()

Ardından, ilk argümandan geriye kalanlar tekrar geçici olarak ilk karakterine kesilir - ki şimdi tek bir bayt olacağından emin olunmalıdır. Bu ilk bayt, eşleştiği dizenin kuyruğundan soymak için bir referans olarak kullanılır ve referans $b, eval'd konumsal bir parametreyi temsil eder; Diğer üç dizi, konumsal parametrelerden tamamen çıkarılır.

               eval "   set    \"\${$((b+1))%"'\''"${a%"${a#?}"}"*}" "$6"'\''
               a=${a#?};set    "$((b=b*100+${#1}+${#1}/8*2)))" \
                                "$2(o$((c+=1))=$b)>=(d$c=$((0$b)))|"

Bu noktada baytın değeri (modulo 64) dizgenin len değeri olarak belirtilebilir:

str=$(printf '\200\1\2\3\4\5\6\7')
ref=$(printf \\4)
str=${str%"$ref"*}
echo "${#str}"

4

Daha sonra içindeki değere bağlı olarak modülün uzlaştırılması için bir miktar matematik yapılır $b, ilk bayt $asürekli olarak sıyrılır ve mevcut döngünün çıktısı $agerçekte boş olup olmadığını kontrol etmek için geri dönüşümden önce bekleyen bir yığına eklenir .

    eval "   unset   LC_ALL  a b c;${2%?})'\''"
    return  "$((${OPTARG%%\**}-1))"

Ne zaman $aistisna ile - kesinlikle bütün isimlerin ve devlet, boş $OPTARG, yürütme kurs boyunca etkilenen işlev önceki durumuna geri olduğunu - - seti ve boş değil, seti ve boş veya belirlenmemiş kalması olsun - ve çıkış kaydedilir için $OPTARGfonksiyon olarak geri döner. Gerçek dönüş değeri, ilk argümanının ilk karakterindeki toplam bayt sayısından azdır - bu nedenle herhangi bir bayt karakteri sıfır döndürür ve herhangi bir çok baytlık karakter sıfırdan fazla döndürür - ve çıkış formatı biraz gariptir.

Değeri ctbl()kaydeder $OPTARG, değerlendirilirse, aynı anda formlarının değişken isimleri Sahip olacağı geçerli bir kabuk aritmetik ifadedir $o1, $d1, $o2, $d2ondalık ve ilk argümanının ilk karakteri tüm ilgili bayt sekizlik değerlere ancak toplam değerlendirmek sonuçta ilk argümandaki bayt sayısı. Bunu yazarken aklımda belirli bir iş akışı vardı ve belki de bir gösteri yapıldığını düşünüyorum.

Sıklıkla getoptsbenzer bir dize almak için bir neden buluyorum :

str=some\ string OPTIND=1
while   getopts : na  -"$str"
do      printf %s\\n "$OPTARG"
done

s
o
m
e

s
t
r
i
n
g

Muhtemelen, satır başına char yazdırmaktan biraz daha fazlasını yapıyorum, ancak her şey mümkün. Her durumda, henüz getoptsdüzgün bir şekilde yapacak bir şey bulamadım (grev - dash's getoptschar char, ama bashkesinlikle yok) :

str=ŐőŒœŔŕŖŗŘřŚśŜŝŞş  OPTIND=1
while   getopts : na  -"$str"
do      printf %s\\n "$OPTARG"
done|   od -tc

0000000 305  \n 220  \n 305  \n 221  \n 305  \n 222  \n 305  \n 223  \n
0000020 305  \n 224  \n 305  \n 225  \n 305  \n 226  \n 305  \n 227  \n
0000040 305  \n 230  \n 305  \n 231  \n 305  \n 232  \n 305  \n 233  \n
0000060 305  \n 234  \n 305  \n 235  \n 305  \n 236  \n 305  \n 237  \n
0000100

Tamam. Ben de denedim ...

str=ŐőŒœŔŕŖŗŘřŚśŜŝŞş
while   [ 0 -ne "${#str}" ]
do      printf %c\\n "$str"    #identical results for %.1s
        str=${str#?}
done|   od -tc

#dash
0000000 305  \n 220  \n 305  \n 221  \n 305  \n 222  \n 305  \n 223  \n
0000020 305  \n 224  \n 305  \n 225  \n 305  \n 226  \n 305  \n 227  \n
0000040 305  \n 230  \n 305  \n 231  \n 305  \n 232  \n 305  \n 233  \n
0000060 305  \n 234  \n 305  \n 235  \n 305  \n 236  \n 305  \n 237  \n
0000100

#bash
0000000 305  \n 305  \n 305  \n 305  \n 305  \n 305  \n 305  \n 305  \n
*
0000040

Bu tür bir iş akışı - char türü için bayt / char için bayt - tty işleri yaparken sık sık girdiğim bir iş. Girişin ön ucunda char değerlerini okuduğunuz anda bilmeniz ve boyutlarına (özellikle sütun sayırken) bilmeniz ve karakterlerin tam olması için karakterlere ihtiyacınız vardır .

Ve şimdi ben var ctbl():

str=ŐőŒœŔŕŖŗŘřŚśŜŝŞş
while [ 0 -ne "${#str}" ]
do    ctbl "$str"
      printf "%.$(($OPTARG))s\t::\t$OPTARG\t::\t$?\t::\t\\$o1\\$o2\n" "$str"
      str=${str#?}
done

Ő   ::  2*((o1=305)>=(d1=197)|(o2=220)>=(d2=144))   ::  1   ::  Ő
ő   ::  2*((o1=305)>=(d1=197)|(o2=221)>=(d2=145))   ::  1   ::  ő
Œ   ::  2*((o1=305)>=(d1=197)|(o2=222)>=(d2=146))   ::  1   ::  Œ
œ   ::  2*((o1=305)>=(d1=197)|(o2=223)>=(d2=147))   ::  1   ::  œ
Ŕ   ::  2*((o1=305)>=(d1=197)|(o2=224)>=(d2=148))   ::  1   ::  Ŕ
ŕ   ::  2*((o1=305)>=(d1=197)|(o2=225)>=(d2=149))   ::  1   ::  ŕ
Ŗ   ::  2*((o1=305)>=(d1=197)|(o2=226)>=(d2=150))   ::  1   ::  Ŗ
ŗ   ::  2*((o1=305)>=(d1=197)|(o2=227)>=(d2=151))   ::  1   ::  ŗ
Ř   ::  2*((o1=305)>=(d1=197)|(o2=230)>=(d2=152))   ::  1   ::  Ř
ř   ::  2*((o1=305)>=(d1=197)|(o2=231)>=(d2=153))   ::  1   ::  ř
Ś   ::  2*((o1=305)>=(d1=197)|(o2=232)>=(d2=154))   ::  1   ::  Ś
ś   ::  2*((o1=305)>=(d1=197)|(o2=233)>=(d2=155))   ::  1   ::  ś
Ŝ   ::  2*((o1=305)>=(d1=197)|(o2=234)>=(d2=156))   ::  1   ::  Ŝ
ŝ   ::  2*((o1=305)>=(d1=197)|(o2=235)>=(d2=157))   ::  1   ::  ŝ
Ş   ::  2*((o1=305)>=(d1=197)|(o2=236)>=(d2=158))   ::  1   ::  Ş
ş   ::  2*((o1=305)>=(d1=197)|(o2=237)>=(d2=159))   ::  1   ::  ş

Not ctbl()aslında tanımlamıyor $[od][12...]değişkenleri - herhangi durumuna herhangi kalıcı bir etkiye sahiptir ama asla $OPTARG- ama sadece dize koyar $OPTARGo kullanılabilir onları tanımlamak - Yukarıdaki yaparak ben her char ikinci kopyasını almak nasıl olduğu printf "\\$o1\\$o2", çünkü Her değerlendirdiğimde belirleniyorlar $(($OPTARG)). Ama aynı zamanda bir alan uzunluğu değiştirici ilan ediyorum bunu nerede printf'ın %sdize argümanı biçimi ve ifadesi her zaman bir karakterin bayt sayısı olarak değerlendirildiğinden, o zaman da, ben çıkışına bütün karakter olsun:

printf %.2s "$str"

Şaşkın bir bash kod yarışmasında yarışmalısınız!
HelloGoodbye

1
@HelloGoodbye bu ish bash kodu . ne de bu karışık değildir. şaşkınlığı görmek için, lütfen [ "$(printf \\1)" ]|| ! echo but its not null!bu arada bakın, bu tür bir yarışma önermedikçe, anlamlı yorum pratiği hakkında daha iyi bilgi almaktan çekinmeyin…?
mikeserv

Hayır, bilmiyorum, yazdıklarım kodunuzun çok kafa karıştırıcı olduğunu söylemenin başka bir yoluydu (en azından benim için), ama belki de kolayca anlaşılabilir olması gerekmiyordu. Eğer bash değilse, o zaman hangi dil?
HelloGoodbye

@HelloGoodbye - Bu POSIX shkomut dilidir. yine aynı suprasete sahip bashbir bururdur ve büyük oranda yukarıda geniş çapta portatif, kendiliğinden genişleyen ve herhangi bir türden onurlandırılabilir karakter boyutlarına yönelik sağladığı bakımın büyük bir kısmı için hızlı bir harekete geçiricidir. Bunların çoğunu zaten halletmeliyiz, ancak dil yukarıda verilen yeterliliğe sahipti ve belki de yetersizdi. bashcprintf
mikeserv

Basitlik ve okunabilirlik adına printf "% d" "'$ char" kullanma eğilimindeyim. Bu @ mikeserv'in çözüm adreslerine ne gibi sorunlar getirdiğini merak ediyorum? Dönüş kodunu etkileyen bazı kontrol karakterlerinden daha fazlası var mı (yukarıdaki yorumdaki amacına inanıyorum)?
Alex Jansen

3

Bir kabuk betiği değil, çalışıyor

awk 'BEGIN{for( i=97; i<=122;i++) printf "%c %d\n",i,i }'  

Örnek çıktı

xieerqi:$ awk 'BEGIN{for( i=97; i<=122;i++) printf "%c %d\n",i,i }' | head -n 5                                    
a 97
b 98
c 99
d 100
e 101

2
  • sembolünü seçin, ardından CTRL + C tuşlarına basın.
  • açık konsole
  • ve türü: xxd<press enter>
  • sonra tuşuna basın <SHIFT+INSERT><CTRL+D>

Gibi bir şey olsun:

mariank@dd903c5n1 ~ $ xxd
û0000000: fb 

yapıştırdığın sembolün hex kodu olduğunu biliyorsun 0xfb

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.