Відповіді:
Визначте ці дві функції (як правило, доступні іншими мовами):
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
konsole
xxd<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'
мати його у вісімці))