web-dev-qa-db-fra.com

Script Bash pour obtenir ASCII valeurs pour l'alphabet

Comment obtenir la valeur ASCII de l'alphabet?

Par exemple, 97 pour a?

53
xmpirate

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
76
dsmsk80

Vous pouvez voir l'ensemble complet avec:

$ man ascii

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

20
ford

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'.
14
Saravanan

Si vous souhaitez l'étendre aux caractères UTF-8 (en supposant que vous êtes dans un environnement local UTF-8):

$ Perl -CA -le 'print ord shift' ????
128520

$ Perl -CS -le 'print chr shift' 128520
????

Avec bash, ksh ou zsh intégrés:

$ printf "\U$(printf %08x 128520)\n"
????
13
Stéphane Chazelas

J'opte pour la solution Bash simple (et élégante?):

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

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

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

Remarquez le devis unique avant CharValue. C'est obligatoire ...

6
phulstaert
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))"
}'

Le premier ctbl() - en haut là-bas - ne s'exécute qu'une seule fois. Il génère la sortie suivante (qui a été filtrée à travers sed -n l Pour l'imprimabilité):

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

... qui sont tous des octets de 8 bits (moins NUL), divisé en quatre chaînes entre guillemets réparties uniformément aux limites de 64 octets. Les chaînes 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 espace réservé pour NUL.

Le premier but de l'existence de ctbl() est de générer ces chaînes afin que eval puisse définir la deuxième 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. Lorsque eval définit la deuxième fonction ctbl(), la première cesse d'être.

La moitié supérieure de la deuxième fonction ctbl() est principalement accessoire ici - elle est conçue pour sérialiser de manière portative et en toute sécurité tout état Shell actuel qu'il pourrait affecter lors de son appel. La boucle supérieure cite toutes les citations dans les valeurs de toutes les variables qu'elle peut vouloir utiliser, puis empile tous les résultats dans ses paramètres de position.

Les deux premières lignes, cependant, retournent d'abord immédiatement 0 et définissent $OPTARG Sur le même si le premier argument de la fonction ne contient pas au moins un caractère. Et si c'est le cas, la deuxième ligne tronque immédiatement son premier argument à son premier caractère uniquement, car la fonction ne gère qu'un caractère à la fois. Surtout, il le fait dans le contexte local actuel, ce qui signifie que si un caractère peut comprendre plus d'un seul octet, à condition que le Shell prenne correctement en charge les caractères multi-octets, il ne supprimera aucun octet, sauf ceux qui ne sont pas dans le premier caractère de son premier argument.

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

Il effectue ensuite la boucle de sauvegarde si cela est nécessaire, puis redéfinit le contexte de paramètres régionaux actuel en paramètres régionaux C pour chaque catégorie en attribuant à la variable LC_ALL. À 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 chacun adressables en tant que caractères individuels à part entière.

        LC_ALL=C

C'est pour cette raison que la seconde moitié de la fonction est un whileboucle, par opposition à une séquence exécutée individuellement. Dans la plupart des cas, il ne s'exécutera probablement qu'une seule fois par appel, mais si le shell dans lequel ctbl() est correctement défini gère les caractères multi-octets, il pourrait 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 commande $(ctbl) ci-dessus n'est évaluée qu'une seule fois - par eval lorsque la fonction est initialement définie - et que pour toujours après ce jeton est remplacé par la sortie littérale de cette substitution de commande enregistrée dans la mémoire du Shell. Il en va de même pour les deux substitutions de commande de modèle case. Cette fonction n'appelle jamais un sous-shell ou toute autre commande. Il n'essaiera pas non plus de lire ou d'écrire les entrées/sorties (sauf dans le cas de certains messages de diagnostic Shell - qui indiquent probablement un bogue).

Notez également que le test de continuité de boucle n'est pas simplement [ -n "$a" ], Car, 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 le len de $a à 0 pour chaque itération, qui, également inexplicablement, se comporte différemment (lire: correctement).

case vérifie le premier octet à inclure dans l'une de nos quatre chaînes et stocke une référence à l'ensemble d'octets dans $b. Ensuite, les quatre premiers paramètres positionnels du Shell sont set dans les chaînes incorporées par eval et écrites par le prédécesseur de ctbl().

Ensuite, tout ce qui reste du premier argument est à nouveau temporairement tronqué à son premier caractère - qui devrait maintenant être assuré d'être un seul octet. Ce premier octet est utilisé comme référence pour supprimer la queue de la chaîne à laquelle il correspond et la référence dans $b Est eval 'd pour représenter un paramètre positionnel, donc tout, de l'octet de référence à le dernier octet de la chaîne peut être remplacé. Les trois autres chaînes sont entièrement supprimées des paramètres 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 le len de la chaîne:

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

4

Un peu de calcul est ensuite effectué pour réconcilier le module en fonction de la valeur dans $b, Le premier octet de $a Est définitivement supprimé et la sortie pour le cycle en cours est ajoutée à une pile en attendant la fin. avant que la boucle ne recycle pour vérifier si $a est réellement vide.

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

Lorsque $a Est définitivement vide, tous les noms et états - à l'exception de $OPTARG - que la fonction affectée tout au long de son exécution sont restaurés à leur état précédent - qu'elle soit définie et non nulle, définie et nulle ou non définie - et la sortie est enregistrée dans $OPTARG lorsque la fonction revient. La valeur de retour réelle est inférieure de un au nombre total d'octets dans le premier caractère de son premier argument - donc tout caractère à un octet renvoie zéro et tout caractère multi-octets retournera plus de zéro - et son format de sortie est un peu étrange.

La valeur que ctbl() enregistre dans $OPTARG Est une expression arithmétique Shell valide qui, si elle est évaluée, définira simultanément les noms de variables des formulaires $o1, - $d1, $o2, $d2 aux valeurs décimales et octales de tous les octets respectifs dans le premier caractère de son premier argument, mais finalement évaluer le nombre total d'octets dans son premier argument. J'avais un type de flux de travail spécifique à l'esprit lorsque j'écris ceci, et je pense qu'une démonstration est peut-être nécessaire.

Je trouve souvent une raison de démonter une chaîne avec getopts comme:

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

Je fais probablement un peu plus que simplement l'imprimer en caractères par ligne, mais tout est possible. En tout cas, je n'ai pas encore trouvé un getopts qui fera correctement (biffez que - dash est getopts 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 type de flux de travail - l'octet pour l'octet/char pour le type char - est celui dans lequel j'entre souvent lorsque je fais des trucs tty. Au premier bord de l'entrée, vous devez connaître les valeurs de caractères dès que vous les lisez, et vous avez besoin de leurs tailles (en particulier lors du comptage des colonnes), et vous avez besoin que les caractères soient entier caractères.

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 met seulement la chaîne dans $OPTARG que peut être utilisé pour les définir - c'est ainsi que j'obtiens la deuxième copie de chaque caractère ci-dessus en faisant printf "\\$o1\\$o2" car ils sont définis chaque fois que j'évalue $(($OPTARG)) . Mais là où je le fais, je déclare également un modificateur de longueur de champ au format d'argument de chaîne %s De printf, et parce que l'expression est toujours évaluée au nombre total d'octets dans un caractère, j'obtiens le caractère entier en sortie quand je fais:

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

vous obtenez quelque chose comme:

mariank@dd903c5n1 ~ $ xxd
û0000000: fb 

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

3
Marian Klen

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
3