Respuestas:
Defina estas dos funciones (generalmente disponibles en otros idiomas):
chr() {
[ "$1" -lt 256 ] || return 1
printf "\\$(printf '%03o' "$1")"
}
ord() {
LC_CTYPE=C printf '%d' "'$1"
}
Uso:
chr 65
A
ord A
65
printf "\\$(printf '%03o' "$1")", '%03o', LC_CTYPE=Cy la comilla simple en "'$1"Do?
Puedes ver todo el conjunto con:
$ man ascii
Obtendrá tablas en octal, hexadecimal y decimal.
Si desea extenderlo a los caracteres UTF-8:
$ perl -CA -le 'print ord shift' 😈
128520
$ perl -CS -le 'print chr shift' 128520
😈
Con bash, ksho zshlas órdenes internas:
$ printf "\U$(printf %08x 128520)\n"
😈
iceweaselen Debian sid. La fuente confirmada por la consola web de iceweasel es "DejaVu Sans" y tengo instalados los paquetes ttf-dejavu ttf-dejavu-core ttf-dejavu-extra que provienen de Debian con upstream en dejavu-fonts.org
Esto funciona 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.
exactamente equivalente a:
echo -n "A" | od -An -tuC ### Not all shells honor the '-n'.
echo -nsuprime la nueva línea final eliminando la necesidad detr -d "\n"
echo, no en ecos compatibles con Unix, por ejemplo. printf %s ASería el portátil.
Voy por la solución Bash simple (y elegante?):
for i in {a..z}; do echo $(printf "%s %d" "$i" "'$i"); done
En un script puedes usar lo siguiente:
CharValue="A"
AscValue=`printf "%d" "'$CharValue"
Observe la comilla simple antes de CharValue. Está obligado ...
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))"
}'
El primero ctbl(), en la parte superior, solo se ejecuta una vez. Genera el siguiente resultado (que se ha filtrado a través sed -n lde la capacidad de impresión) :
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"$
... que son todos bytes de 8 bits (menos NUL) , divididos en cuatro cadenas entre comillas divididas de manera uniforme en los límites de 64 bytes. Las cuerdas pueden ser representados con rangos octales gusta \200\1-\77, \100-\177, \200-\277, \300-\377, donde byte 128 se utiliza como un lugar-soporte para NUL.
El primer ctbl()propósito de la existencia del primero es generar esas cadenas para que evalpuedan definir la segunda ctbl()función con ellas literalmente incrustadas a partir de entonces. De ese modo, se puede hacer referencia a ellos en la función sin necesidad de generarlos nuevamente cada vez que se necesiten. Cuando evaldefine la segunda ctbl()función, la primera dejará de ser.
La mitad superior de la segunda ctbl()función es principalmente auxiliar aquí: está diseñada para serializar de forma portátil y segura cualquier estado de shell actual que pueda afectar cuando se llama. El bucle superior citará las comillas en los valores de cualquier variable que quiera usar, y luego apilará todos los resultados en sus parámetros posicionales.
Sin embargo, las dos primeras líneas devuelven inmediatamente 0 y se establecen $OPTARGen el mismo si el primer argumento de la función no contiene al menos un carácter. Y si lo hace, la segunda línea trunca inmediatamente su primer argumento solo a su primer carácter, porque la función solo maneja un carácter a la vez. Es importante destacar que hace esto en el contexto local actual, lo que significa que si un carácter puede comprender más de un byte, entonces, siempre que el shell admita caracteres de varios bytes, no descartará ningún byte excepto aquellos que no están en el primer personaje de su primer argumento.
${1:+":"} return "$((OPTARG=0))"
set "" "" "${1%"${1#?}"}"
Luego realiza el ciclo de guardar si es necesario, y luego redefine el contexto de la configuración regional actual a la configuración regional C para cada categoría mediante la asignación a la LC_ALLvariable. A partir de este momento, un carácter solo puede consistir en un solo byte, por lo que si hubiera varios bytes en el primer carácter de su primer argumento, ahora estos deberían ser direccionables como caracteres individuales por derecho propio.
LC_ALL=C
Es por esta razón que la segunda mitad de la función es un while bucle , a diferencia de una secuencia de ejecución individual. En la mayoría de los casos, probablemente se ejecutará solo una vez por llamada, pero, si el shell en el que ctbl()se define correctamente maneja los caracteres de varios bytes, podría repetirse.
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)"' "$@"
Tenga en cuenta que la anterior $(ctbl)sustitución comando sólo se evalúa una vez cada vez - por evalcuando la función se define inicialmente - y que siempre después de que el distintivo se sustituye por la salida literal de que la sustitución de comandos como guarda en la memoria de la cáscara. Lo mismo es cierto para las dos casesustituciones de comando de patrón. Esta función nunca llama a un subshell ni a ningún otro comando. Tampoco intentará leer o escribir entradas / salidas (excepto en el caso de algún mensaje de diagnóstico de shell, que probablemente indica un error) .
También tenga en cuenta que la prueba de continuidad del bucle no es simplemente [ -n "$a" ], porque, como descubrí para mi frustración, por alguna razón un bashshell lo hace:
char=$(printf \\1)
[ -n "$char" ] || echo but it\'s not null\!
but it's not null!
... y entonces comparo explícitamente $alen a 0 para cada iteración, que, también inexplicablemente, se comporta de manera diferente (léase: correctamente) .
Los casecheques el primer byte para su inclusión en cualquiera de nuestros cuatro cuerdas y almacena una referencia al conjunto del byte $b. Luego, los primeros cuatro parámetros posicionales del shell son setlas cadenas incrustadas evaly escritas por ctbl()el predecesor.
A continuación, lo que queda del primer argumento se vuelve a truncar temporalmente a su primer carácter, que ahora debe asegurarse de que sea un solo byte. Este primer byte se utiliza como una referencia a la tira de la cola de la cadena de la que corresponde y la referencia en $bestá eval'd para representar un parámetro de posición de modo de todo, desde el byte de referencia al último byte en la cadena puede ser sustituido de distancia. Las otras tres cadenas se eliminan completamente de los parámetros posicionales.
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)))|"
En este punto, el valor del byte (módulo 64) puede referenciarse como el len de la cadena:
str=$(printf '\200\1\2\3\4\5\6\7')
ref=$(printf \\4)
str=${str%"$ref"*}
echo "${#str}"
4
Luego se hace un poco de matemática para conciliar el módulo en función del valor $b, el primer byte $ase elimina permanentemente y la salida para el ciclo actual se agrega a una pila hasta que se complete antes de que el ciclo se recicle para verificar si $aestá realmente vacío.
eval " unset LC_ALL a b c;${2%?})'\''"
return "$((${OPTARG%%\**}-1))"
Cuando $adefinitivamente está vacío, todos los nombres y estados, con la excepción de $OPTARGque la función afectada a lo largo de su ejecución se restaura a su estado anterior, ya sea establecido y no nulo, establecido y nulo o sin establecer, y la salida se guarda a $OPTARGcomo vuelve la función. El valor de retorno real es uno menos que el número total de bytes en el primer carácter de su primer argumento, por lo que cualquier carácter de un solo byte devuelve cero y cualquier carácter de varios bytes devolverá más de cero, y su formato de salida es un poco extraño.
El valor ctbl()se guarda en $OPTARGuna cáscara de expresión aritmética válido que, si se evalúa, fijará al mismo tiempo los nombres de variables de las formas $o1, $d1, $o2, $d2al decimal y los valores octales de todos los bytes respectivos en el primer carácter de su primer argumento, pero en última instancia evaluar al total número de bytes en su primer argumento. Tenía un tipo específico de flujo de trabajo en mente al escribir esto, y creo que tal vez sea necesario hacer una demostración.
A menudo encuentro una razón para separar una cadena con getoptslike:
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
Probablemente haga un poco más que imprimirlo en un carácter por línea, pero todo es posible. En cualquier caso, todavía no he encontrado una getoptsque va a hacer correctamente (huelga que - dashEs getoptslo hace charla por char, pero bashdefinitivamente no lo hace) :
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
Okay. Entonces intenté ...
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
Ese tipo de flujo de trabajo, el byte para byte / char para char kind, es uno en el que a menudo me meto cuando hago cosas de tty. En la vanguardia de la entrada, debe conocer los valores de caracteres tan pronto como los lea, y necesita sus tamaños (especialmente al contar columnas) , y necesita que los caracteres sean caracteres enteros .
Y ahora tengo 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 :: ş
Tenga en cuenta que en ctbl()realidad no define las $[od][12...]variables, nunca tiene un efecto duradero en ningún estado $OPTARG, pero solo coloca la cadena $OPTARGque se puede usar para definirlas, que es la forma en que obtengo la segunda copia de cada carácter anterior printf "\\$o1\\$o2"porque se establecen cada vez que evalúo $(($OPTARG)). Pero cuando lo hago también estoy declarando un modificador de la longitud del campo de printf's %sformato argumento de cadena, y debido a la expresión da siempre como resultado el número total de bytes de un personaje, me sale todo el carácter en la salida cuando lo haga:
printf %.2s "$str"
[ "$(printf \\1)" ]|| ! echo but its not null!mientras tanto, siéntase libre de familiarizarse mejor con la práctica de comentarios significativos, a menos que recomiende un concurso real de este tipo ...?
shlenguaje de comando POSIX . bashes un bourne nuevamente superior de lo mismo, y en gran parte un motivador precipitado para gran parte de la atención brindada anteriormente hacia tamaños de caracteres honorables de gran tamaño, portátiles y autoexpandibles de cualquier tipo. bashya debería manejar gran parte de esto, pero el clenguaje printfera, y tal vez es, deficiente la capacidad proporcionada anteriormente.
No es un script de shell, pero funciona
awk 'BEGIN{for( i=97; i<=122;i++) printf "%c %d\n",i,i }'
Salida de muestra
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
konsolexxd<press enter><SHIFT+INSERT><CTRL+D>obtienes algo como:
mariank@dd903c5n1 ~ $ xxd
û0000000: fb
sabes que el símbolo que pegaste tiene código hexadecimal 0xfb
"'A"es correcta, mientras que si se utiliza"A"dirá:A: invalid number. Parece que está hecho en el lado printf (es decir, en el shell, de"'A"hecho hay 2 caracteres, ay'aA. Esos se pasan a printf. Y en el contexto printf, se convierte al valor ascii de A, (y finalmente se imprime como decimal gracias a'%d'. Úselo'Ox%x'para mostrarlo en hexa o'0%o'para tenerlo en octal))