Відповіді:
Визначте ці дві функції (як правило, доступні іншими мовами):
chr() {
[ "$1" -lt 256 ] || return 1
printf "\\$(printf '%03o' "$1")"
}
ord() {
LC_CTYPE=C printf '%d' "'$1"
}
Використання:
chr 65
A
ord A
65
printf "\\$(printf '%03o' "$1")", '%03o', LC_CTYPE=Cі апостроф в "'$1"справах?
Ви можете побачити весь набір за допомогою:
$ man ascii
Ви отримаєте таблиці в восьмеричній, шістнадцятковій і десятковій.
Якщо ви хочете розширити його на символи UTF-8:
$ perl -CA -le 'print ord shift' 😈
128520
$ perl -CS -le 'print chr shift' 128520
😈
З bash, kshабо zshвбудовані:
$ printf "\U$(printf %08x 128520)\n"
😈
iceweaselна Debian sid. Шрифт, підтверджений веб-консоллю iceweasel, є "DejaVu Sans", і у мене встановлені додаткові пакети ttf-dejavu ttf-dejavu-core ttf-dejavu-додаткові пакети, які надходять з Debian вгору за течією на dejavu-fonts.org
Це добре працює,
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.
точно рівнозначно:
echo -n "A" | od -An -tuC ### Not all shells honor the '-n'.
echo -nпригнічує tr -d "\n"
echo, не в сумісних відгомонах Unix. printf %s Aбув би переносним.
Я збираюся просте (і елегантне?) Рішення Bash:
for i in {a..z}; do echo $(printf "%s %d" "$i" "'$i"); done
Для сценарію ви можете використовувати наступне:
CharValue="A"
AscValue=`printf "%d" "'$CharValue"
Зверніть увагу на єдину цитату перед CharValue. Це зобов'язане ...
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))"
}'
Перший ctbl()- на вершині там - пробігає лише один раз. Він генерує такий вихід (який був відфільтрований sed -n lзаради друку) :
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"$
... які є 8-бітовими байтами (менше NUL) , розділеними на чотири рядки, цитовані оболонкою, розділені рівномірно на 64-байтові межі. Можуть бути представлені рядки з вісімковій діапазони подобається \200\1-\77, \100-\177, \200-\277, \300-\377, де байти 128 використовуються в якості місця для держателя NUL.
Перша ctbl()вся мета існування - генерувати ці рядки, щоб вони evalмогли визначати другу ctbl()функцію з ними буквально вбудованою після цього. Таким чином, на них можна посилатись у функції, без необхідності генерувати їх знову щоразу, коли вони знадобляться. Коли evalвизначається друга ctbl()функція, перша перестане бути.
Верхня половина другої ctbl()функції в основному є допоміжною - вона розроблена для портативної та безпечної серіалізації будь-якого поточного стану оболонки, на яку вона може вплинути, коли вона викликається. Верхній цикл цитуватиме будь-які лапки у значеннях будь-яких змінних, які він може використовувати, а потім укладає всі результати у свої позиційні параметри.
Перші два рядки, однак, спочатку повертають 0 і встановлюють таке $OPTARGж, якщо перший аргумент функції не містить принаймні одного символу. І якщо це так, другий рядок негайно обрізає свій перший аргумент лише його першим символом - тому що функція обробляє символ лише за один раз. Важливо, що це робиться в поточному контексті локалі, а це означає, що якщо символ може містити більше одного байта, тоді, якщо оболонка належним чином підтримує багатобайтові символи, вона не відкине жодних байтів, окрім тих, яких немає в Перший персонаж свого першого аргументу.
${1:+":"} return "$((OPTARG=0))"
set "" "" "${1%"${1#?}"}"
Потім це цикл збереження, якщо він є необхідним, а потім переосмислює поточний контекст локалі для мови C для кожної категорії шляхом присвоєння LC_ALLзмінної. З цього моменту символ може складатися лише з одного байту, і тому, якщо в першому символі його першого аргументу було кілька байтів, тепер вони повинні бути адресовані як окремі символи самостійно.
LC_ALL=C
Саме з цієї причини друга половина функції є while циклом , на відміну від послідовно запущеної послідовності. У більшості випадків він, ймовірно, виконуватиметься лише один раз за виклик, але, якщо оболонка, у якій ctbl()визначено належним чином, обробляє багатобайтові символи, вона може зациклюватися.
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)"' "$@"
Зауважимо, що вищезазначена $(ctbl)заміна команд оцінюється лише один раз - evalколи функція спочатку визначена - і назавжди після цього маркер замінюється буквальним результатом цієї заміни команди, як збережений у пам'яті оболонки. Те саме стосується двох caseпідстановок командної схеми. Ця функція ніколи не викликає підзаголовок або будь-яку іншу команду. Він також ніколи не намагатиметься прочитати або записати вхід / вихід (за винятком випадків діагностичного повідомлення оболонки - що, ймовірно, вказує на помилку) .
Також зауважте, що тест на безперервність циклу проводиться не просто [ -n "$a" ], тому що, як я виявив своє розчарування, чомусь bashоболонка робить:
char=$(printf \\1)
[ -n "$char" ] || echo but it\'s not null\!
but it's not null!
... і тому я чітко порівнюю $a'sn з 0 для кожної ітерації, яка, також незрозуміло, поводиться по-різному (читайте: правильно) .
У caseперевіряє перші байти для включення в будь-якому з наших чотирьох рядків і зберігає посилання на набір байті в $b. Після цього перші чотири позиційні параметри оболонки мають setрядки, вбудовані evalта написані ctbl()попередником.
Далі все, що залишилося від першого аргументу, знову тимчасово прирізається до його першого символу - який тепер повинен бути впевнений, що це єдиний байт. Цей перший байт використовується в якості посилання на смуги з хвоста рядка , які воно відповідає і посилання в $bце eval«d , щоб представляти позиційний параметр таким чином , все від опорного байта до останнього байта в рядку може бути замінений геть. Інші три рядки повністю випадають з позиційних параметрів.
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)))|"
У цей момент значення байта (модуль 64) може бути позначене як наголос рядка:
str=$(printf '\200\1\2\3\4\5\6\7')
ref=$(printf \\4)
str=${str%"$ref"*}
echo "${#str}"
4
Потім робиться невелика математика для узгодження модуля на основі значення в $b, перший байт в $aостаточно позбавлений, а вихідний для поточного циклу додається до стека до завершення перед циклом переробляється, щоб перевірити, чи $aдійсно порожній.
eval " unset LC_ALL a b c;${2%?})'\''"
return "$((${OPTARG%%\**}-1))"
Коли $aнапевно порожньо, всі імена та стан - за винятком $OPTARG- що функція, на яку впливає протягом усього її виконання, відновлюється до попереднього стану - незалежно від того, встановлена чи не null, set і null, або unset - і вихід зберігається до $OPTARGповернення функції. Фактичне значення повернення на одиницю менше, ніж загальна кількість байтів у першому символі його першого аргументу - тому будь-який символ одного байта повертає нуль, а будь-який багатобайтовий знак поверне більше нуля - і його вихідний формат трохи дивний.
Значення ctbl()економить $OPTARGє допустимим оболонки арифметичне вираз , яке, якщо оцінені, буде одночасно встановити імена змінних форм $o1, $d1, $o2, $d2в десяткової і вісімковій значень всіх відповідних байтів в першому символі перший аргумент, але в кінцевому рахунку оцінити в загальній складності кількість байт у своєму першому аргументі. Я мав на увазі певний вид робочого процесу, коли писав це, і я думаю, може бути демонстрація в порядку.
Я часто знаходжу причину роз'єднувати рядок з getoptsподібними:
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
Я, мабуть, роблю трохи більше, ніж просто роздруковую це за графіку, але все можливо. У будь-якому випадку, я ще не знайшов , getoptsщо буде правильно робити (удар, - dash«S getoptsробить його обвуглюється на гольця, але , bashбезумовно , не чинить) :
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
Гаразд. Тому я спробував ...
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
Такий робочий процес - байт для байтів / char для типу char - той, до якого я часто потрапляю, роблячи невеликі речі. На передньому краї введення вам потрібно знати значення знаків, як тільки ви їх читаєте, і вам потрібні їх розміри (особливо під час підрахунку стовпців) , і вам потрібні символи, щоб вони були цілими символами.
І ось тепер у мене є 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 :: ş
Зауважте, що ctbl()насправді не визначають $[od][12...]змінні - вона ніколи не має довготривалого впливу на будь-який стан, але $OPTARG- лише вкладає рядок, $OPTARGякий можна використовувати для їх визначення - саме тому я отримую другу копію кожної таблиці вище, роблячи, printf "\\$o1\\$o2"тому що вони встановлюються щоразу, коли я оцінюю $(($OPTARG)). Але де я це роблю я також оголосити довжину поля модифікатор printf«s %sформат рядка аргументу, і тому , що вираз завжди обчислюється на загальне число байтів в характері, я отримую весь характер на виході , коли я роблю:
printf %.2s "$str"
[ "$(printf \\1)" ]|| ! echo but its not null!, сміливо ознайомтеся зі змістовною практикою коментування, якщо ви не рекомендуєте фактичний такий конкурс ...?
shкомандна мова POSIX . bashце знову буржуазний набір того ж самого, і значною мірою - невід'ємний мотиватор для більшої частини турбот, наданих вище до широко портативних, саморозширюваних та просторів імен, почесних розмірів символів будь-якого типу. bashВи повинні вже вирішити багато з цього, але cмова printfбула, і, можливо, є недостатньою для вищезазначених можливостей.
Не сценарій оболонки, але працює
awk 'BEGIN{for( i=97; i<=122;i++) printf "%c %d\n",i,i }'
Вибірка зразка
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>ви отримуєте щось на кшталт:
mariank@dd903c5n1 ~ $ xxd
û0000000: fb
ви знаєте, що символ, який ви вставили, має шістнадцятковий код 0xfb
"'A"правильно тоді , якщо ви використовуєте"A"це буде сказати:A: invalid number. Здається, це зроблено на стороні printf (тобто в оболонці,"'A"дійсно , є два знаки, a'і a),Aякі передаються до printf. як десятковий знак'%d'. Використовуйте,'Ox%x'щоб показати його в шестикутнику або'0%o'мати його у вісімці))