Script Bash pour get des valeurs ASCII pour l'alphabet

Comment get la valeur ASCII de l'alphabet?

Par exemple, 97 pour a ?

Définissez ces deux fonctions (généralement disponibles dans d'autres langues):

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

Usage:

 chr 65 A ord A 65 

Vous pouvez voir l'set avec:

 $ man ascii 

Vous obtiendrez des tables en octal, hexadécimal et décimal.

Cela fonctionne bien,

 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. 

exactement équivalent à:

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

Si vous voulez l'étendre aux caractères UTF-8:

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

Avec bash , ksh ou zsh embedded:

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

Je vais pour la solution simple (et élégante?) Bash:

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

Pour dans un script, vous pouvez utiliser ce qui suit:

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

Notez le devis unique avant le CharValue. C'est obligé …

 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 abc;${2%?})'\''" return "$((${OPTARG%%\**}-1))" }' 

Le premier ctbl() – en haut là – ne fonctionne que la fois. Il génère la sortie suivante (qui a été filtrée via sed -nl pour l'amour de l'imprimabilité) :

 ctbl | sed -nl 

  "\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"$ 

… qui sont tous des octets de 8 bits (less NUL ) , divisés en quatre strings de guillemets divisées divisées à intervalles de 64 octets. Les strings peuvent être représentées avec des plages octales comme \200\1-\77 , \100-\177 , \200-\277 , \300-\377 , où l'octet 128 est utilisé comme support de place pour NUL .

Le but premier de l' ctbl() premier ctbl() est de générer ces strings de sorte eval puisse définir la seconde fonction ctbl() avec elles littéralement incorporées par la suite. De cette façon, ils peuvent être référencés dans la fonction sans avoir besoin de les générer à nouveau chaque fois qu'ils sont nécessaires. Quand eval définit la deuxième fonction ctbl() , la première cessera d'être.

La moitié supérieure de la seconde fonction ctbl() est essentiellement auxiliaire ici – elle est conçue pour sérialiser de manière portable et sécurisée tout état de shell courant auquel il pourrait affecter lorsqu'il est appelé. La boucle supérieure va citer les guillemets dans les valeurs de toutes les variables qu'elle voudra utiliser, puis emstackr tous les résultats dans ses parameters de position.

Les deux premières lignes, cependant, returnnent immédiatement 0 et définissent $OPTARG à la même si le premier argument de la fonction ne contient pas au less un caractère. Et si c'est le cas, la deuxième ligne tronque immédiatement son premier argument à son seul caractère – car la fonction ne traite qu'un caractère à la fois. Il est important de le faire dans le context régional actuel, ce qui signifie que si un caractère peut comprendre plus d'un octet, à condition que le shell supporte correctement les caractères multi-octets, il ne rejettera aucun octet sauf ceux qui ne sont pas dans le context premier caractère de son premier argument.

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

Il effectue ensuite la sauvegarde de la boucle si nécessaire et redéfinit ensuite le context local en cours vers la locale C pour chaque catégorie en l'affectant à la variable LC_ALL . A partir de ce moment, un caractère ne peut être composé que d'un seul octet, et donc s'il y avait plusieurs octets dans le premier caractère de son premier argument, ceux-ci devraient maintenant être adressables individuellement en tant que caractères individuels.

  LC_ALL=C 

C'est pour cette raison que la seconde moitié de la fonction est une boucle while , par opposition à une séquence à exécution unique. Dans la plupart des cas, il ne s'exécutera probablement qu'une fois par appel, mais si le shell dans lequel ctbl() est correctement défini gère les caractères multi-octets, il peut se mettre en boucle.

  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)"' "$@" 

Notez que la substitution de la command $(ctbl) ci-dessus n'est évaluée qu'une seule fois – par eval lorsque la fonction est définie initialement – et que pour toujours, ce jeton est remplacé par la sortie littérale de cette substitution de la command sauvegardée dans la memory du shell. Il en est de même pour les deux substitutions de commands de model de case . Cette fonction n'appelle jamais un sous-shell ou une autre command. Il ne tentera jamais de lire ou d'écrire des inputs / sorties (sauf dans le cas d'un message de diagnostic du shell – qui indique probablement un bogue) .

Notez également que le test de continuité de boucle n'est pas simplement [ -n "$a" ] , parce que, comme je l'ai constaté à ma frustration, pour une raison quelconque, un shell bash fait:

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

 but it's not null! 

… et donc je compare explicitement $a len à 0 pour chaque itération, qui, de manière aussi inexplicable, se comporte différemment (lire correctement) .

Le case vérifie le premier octet pour l'inclusion dans l'une de nos quatre strings et stocke une reference à l'set de l'octet dans $b . Par la suite, les quatre premiers parameters de position du shell sont set sur les strings incorporées par eval et écrites par le ctbl() de ctbl() .

Ensuite, tout ce qui rest du premier argument est temporairement tronqué à son premier caractère – qui devrait maintenant être assuré d'être un seul octet. Ce premier octet est utilisé comme reference pour se désolidariser de la queue de la string à laquelle il correspond et la reference dans $b est eval 'd pour représenter un paramètre de position de sorte que tout de l'octet de reference au dernier octet de la string peut être remplacé . Les trois autres strings sont entièrement supprimées des parameters de position.

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

À ce stade, la valeur de l'octet (modulo 64) peut être référencée comme len de la string:

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

 4 

Un petit calcul est alors fait pour réconcilier le module sur la base de la valeur de $b , le premier octet de $a est supprimé définitivement et la sortie du cycle courant est ajoutée à une stack en attente avant que la boucle ne revienne pour vérifier si $a est réellement vide.

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

Lorsque $a est définitivement vide, tous les noms et états – à l'exception de $OPTARG – que la fonction affectée au cours de son exécution sont restaurés à leur état précédent – set et non null, set et null ou unsset – et la sortie est enregistrée dans $OPTARG fur et à $OPTARG que la fonction returnne. La valeur de return réelle est de un less que le nombre total d'octets dans le premier caractère de son premier argument. Ainsi, tout caractère d'octet unique renvoie zéro et tout caractère multi-octets renvoie plus de zéro et son format de sortie est un peu étrange.

La valeur ctbl() enregistre dans $OPTARG est une expression arithmétique shell valide qui, si elle est évaluée, définira simultanément les noms de variable des forms $o1 , $d1 , $o2 , $d2 en valeurs décimales et octales de tous les octets premier caractère de son premier argument, mais finalement évaluer le nombre total d'octets dans son premier argument. J'avais en tête un type particulier de stream de travail en écrivant cela, et je pense qu'une démonstration est peut-être en cours.

Je trouve souvent une raison de prendre une ficelle à part avec getopts comme:

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

 s o m e s t r i n g 

Je fais probablement un peu plus que d'imprimer un caractère par ligne, mais tout est possible. En tout cas, je n'ai pas encore trouvé un getopts qui le fera correctement (ssortingke that – getopts dash le fait char par char, mais bash ne le fait certainement pas) :

 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 

D'accord. J'ai donc essayé …

 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 

Ce genre de stream de travail – l'octet d'octet / char pour le type de char – est celui que je rentre souvent quand je fais des trucs tty. À l'avant-garde de l'input, vous devez connaître les valeurs char dès que vous les avez lues, et vous avez besoin de leurs tailles (en particulier lors du comptage des colonnes) , et vous avez besoin que les caractères soient des caractères entiers .

Et maintenant, j'ai 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 :: ş 

Notez que ctbl() ne définit pas réellement les variables $[od][12...] – il n'a jamais d'effet durable sur aucun état mais $OPTARG – mais ne met que la string dans $OPTARG qui peut être utilisée pour définir (c'est-à-dire comment j'obtiens la deuxième copy de chaque char ci-dessus en exécutant printf "\\$o1\\$o2" car ils sont définis chaque fois que $(($OPTARG)) . Mais là où je le fais, je déclare également un modificateur de longueur de champ au format d'argument de string %s de printf , et comme l'expression évalue toujours le nombre total d'octets dans un caractère, j'obtiens tout le caractère en sortie quand je le fais :

 printf %.2s "$str" 
  • select le symbole, puis appuyez sur CTRL + C
  • konsole ouvert
  • et tapez: xxd<press enter>
  • puis appuyez sur <SHIFT+INSERT><CTRL+D>

vous obtenez quelque chose comme:

 mariank@dd903c5n1 ~ $ xxd û0000000: fb 

vous savez que le symbole que vous avez collé a le code hexadécimal 0xfb

Pas un script shell, mais fonctionne

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

Exemple de sortie

 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