Yanıtlar:
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
printf "\\$(printf '%03o' "$1")"
, '%03o'
, LC_CTYPE=C
ve de tek tırnak "'$1"
do?
Setin tamamını aşağıdakiler ile görebilirsiniz:
$ man ascii
Sekizli, onaltılı ve ondalık tabloları alırsınız.
UTF-8 karakterlerine genişletmek istiyorsanız:
$ perl -CA -le 'print ord shift' 😈
128520
$ perl -CS -le 'print chr shift' 128520
😈
İle bash
, ksh
veya zsh
builtins:
$ printf "\U$(printf %08x 128520)\n"
😈
iceweasel
on 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
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'.
echo -n
İhtiyacı ortadan kaldıran sondaki newline'ı bastırıyortr -d "\n"
echo
örneğin Unix uyumlu ekolarda değil, sadece bazı uygulamalarda . printf %s A
taşınabilir olanı olurdu.
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 ...
printf "%d"
.
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 l
Yazdı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 eval
ikinci 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 $OPTARG
iş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_ALL
değ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 - eval
fonksiyon 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 case
komut 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 bash
kabuğun yaptığı:
char=$(printf \\1)
[ -n "$char" ] || echo but it\'s not null\!
but it's not null!
... ve böylece $a
her 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ığı set
dizgilerdir .eval
ctbl()
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 $a
sürekli olarak sıyrılır ve mevcut döngünün çıktısı $a
gerç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 $a
istisna 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 $OPTARG
fonksiyon 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
, $d2
ondalı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 getopts
benzer 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 getopts
düzgün bir şekilde yapacak bir şey bulamadım (grev - dash
's getopts
char char, ama bash
kesinlikle 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 $OPTARG
o 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 %s
dize 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"
[ "$(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…?
sh
komut dilidir. yine aynı suprasete sahip bash
bir 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. bash
c
printf
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
konsole
xxd<press enter>
<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
"'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 aA
. 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))