Сценарий Bash для получения значений ASCII для алфавита

Если я понимаю правильно, Вы хотите это:

find /path -mindepth 2 -type f -not -perm 0755

Или возможно просто это, если мое понимание прочь:

find /path/to -type f -not -perm 0755
52
26.09.2013, 11:01
9 ответов

Определите эти две функции (обычно доступный на других языках):

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

ord() {
  LC_CTYPE=C printf '%d' "'$1"
}

Использование:

chr 65
A

ord A
65
75
27.01.2020, 19:33
  • 1
    @dmsk80: +1. Для других как я, которые думают, что определяют опечатку: "'A" корректно тогда как, если Вы используете "A" это скажет: A: invalid number . Кажется, что это сделано на printf стороне (т.е., в оболочке, "'A" действительно 2 символа, a ' и a A. Они передаются printf. И в printf контексте, это преобразовывается в значение ASCII A, (и наконец печатается как десятичное число благодаря '%d'. Использовать 'Ox%x' показать его в hexa или '0%o' иметь его в восьмеричном)) –  Olivier Dulac 26.09.2013, 14:05
  • 2
    1 для того, чтобы не объяснять, как это работает... шутя :D, но серьезно что делает их printf "\\$(printf '%03o' "$1")", '%03o', LC_CTYPE=C и одинарная кавычка в "'$1" ? –  razzak 04.12.2014, 21:42
  • 3
    Read в FAQ 71. Превосходный подробный анализ. –   03.11.2015, 11:22

Вы видите весь набор с:

$ man ascii

Вы вложите таблицы, восьмеричные, шестнадцатеричные, и десятичные.

20
27.01.2020, 19:33
  • 1
    Существует также пакет ASCII для находящихся в debian дистрибутивов, но (по крайней мере теперь) вопрос отмечен как удар, таким образом, они не помогли бы OP. На самом деле это установлено в моей системе и всем, что я получаю от ASCII человека, его страница справочника. –  Joe 28.09.2013, 00:47

Если Вы хотите расширить его до символов UTF-8 (предполагающий, что Вы находитесь в локали UTF-8):

$ perl -CA -le 'print ord shift'  
128520

$ perl -CS -le 'print chr shift' 128520
 

С bash, ksh или zsh builtins:

$ printf "\U$(printf %08x 128520)\n"
 
13
27.01.2020, 19:33
  • 1
    Сделал Вы намереваетесь поместить квадратный символ поля, или иначе затем исходный символ не отображается в сообщении и заменяется квадратным символом поля. –  mtk 02.10.2013, 10:11
  • 2
    @mtk, Вам нужен браузер, который отображает UTF-8 и шрифт, который имеет те 128 520 символов. –  Stéphane Chazelas 02.10.2013, 10:13
  • 3
    я нахожусь на Последнем Chrome и не думаю, что он не поддерживает UTF-8. Хотел бы знать, какой браузер Вы идете? –  mtk 02.10.2013, 11:53
  • 4
    @mtk редактирования, iceweasel на Debian sid. Шрифтом, как подтверждено веб-консолью iceweasel является "DejaVu Sans", и у меня есть ttf-dejavu ttf-dejavu-core ttf-dejavu-extra пакеты, установленные, которые прибывают из Debian с восходящим потоком в dejavu-fonts.org –  Stéphane Chazelas 02.10.2013, 12:10
  • 5
    спасибо, какова основа 128 520? мое собственное ctbl() кажется, правильно позволяет мне отобразить его и отрезать символ от верхней части строки с printf, но это помещает 4*((o1=360)>=(d1=240)|(o2=237)>=(d2=159)|(o3=230)>=(d3=152)|(o4=210)>=(d4=136)) в $OPTARG для значений байта. –  mikeserv 18.11.2015, 07:52

Это работает хорошо,

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'.
14
27.01.2020, 19:33
  • 1
    Можно ли, возможно, добавить маленькое объяснение? –  Bernhard 26.09.2013, 15:04
  • 2
    tr для удаления "\n" (новая строка) из входа. передозировка привыкла к-t dC, должен распечатать в десятичном символе. –  Saravanan 26.09.2013, 15:42
  • 3
    echo -n подавляет запаздывание новой строки, избавляющей от необходимости tr -d "\n" –  Gowtham 26.09.2013, 19:59
  • 4
    @Gowtham, только с некоторыми реализациями echo, не в Unix совместимый echos, например. printf %s A был бы портативный. –  Stéphane Chazelas 27.09.2013, 11:44

Я иду для простого (и изящный?) Решение для Bash:

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

Поскольку в сценарии можно использовать следующее:

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

Заметьте одинарную кавычку перед CharValue. Это обязано...

6
27.01.2020, 19:33
  • 1
    Как Ваш ответ отличается от ответа dsmsk80? –  Bernhard 26.09.2013, 17:35
  • 2
    Моя интерпретация вопроса, "как получить значения ASCII для значений алфавита". Не, как определить функцию для получения значения ASCII для одного символа. Таким образом, мой первый ответ является короткой короткой командой для получения значений ASCII для алфавита. –  phulstaert 27.09.2013, 10:26
  • 3
    я понимаю Вашу мысль, но я все еще думаю нижняя строка обоих ответов, printf "%d". огромное спасибо –  Bernhard 27.09.2013, 12:11
  • 4
    я согласовываю это, является ключевой ролью процесса для получения до результата, все же я не сделал требуемый для создания предположения, что xmpirate знал о "поскольку я в" и использование диапазона. Если бы он хотел список, то это могло бы сэкономить время ;-). Кроме того, будущие читатели могли бы найти мои дополнения полезными. –  phulstaert 27.09.2013, 12:44
  • выберите символ, затем нажмите CTRL+C
  • откройте konsole
  • и введите: xxd<нажмите enter>
  • затем нажмите

вы получите что-то вроде:

mariank@dd903c5n1 ~ $ xxd
û0000000: fb 

вы знаете, что символ, который вы вставили, имеет шестнадцатеричный код 0xfb

3
27.01.2020, 19:33

Не сценарий оболочки, но работает

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
3
27.01.2020, 19:33
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 -nl для удобства печати) :

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!

... и поэтому я явно сравниваю len $ a с 0 для каждой итерации, которая также необъяснимо ведет себя по-разному (читай: правильно) .

Случай проверяет первый байт на предмет включения в любую из наших четырех строк и сохраняет ссылку на набор байтов в $ b . После этого первые четыре позиционных параметра оболочки устанавливаются в строки, встроенные 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, установлен и равен нулю или не установлен - и вывод сохраняется в $ 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 getopts делает это char за char , но 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 - я часто использую при выполнении tty-вещей. На переднем крае ввода вам нужно знать значения 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 )) . Но там, где я это делаю, я также объявляю модификатор длины поля для строкового аргумента % s printf ], и поскольку выражение всегда оценивает общее количество байтов в символ, я получаю на выходе весь символ, когда делаю это:

printf %.2s "$str"
6
27.01.2020, 19:33

Если вы хотите распечатать десятичное представление значения UTF -8, я одобряю решение dsmsk80. Если, с другой стороны, вам нужно присвоить значение переменной, в Bash есть механизм printf, который работает быстрее. Предположим, что вы хотите присвоить значение ascii "A" (, которое равно 65 в десятичной системе и которое мы присвоили переменнойtheChar)переменной myVar. Вставив функцию ord()dmsmsk80, мы получим:

LC_CTYPE=C myVar=$(printf "%d" "'$theChar")

Чтобы это присвоение имело место, значение, полученное из '$theChar, должно быть отформатировано в десятичных символах, а затем преобразовано из десятичного числа в число 65, которое затем сохраняется в myVar. Чтобы избежать этого форматирования и синтаксического анализа, мы можем воспользоваться флагом -vдля printf, который присваивает значение, которое будет напечатано напрямую. Синтаксис следующий:

LC_CTYPE=C printf -v myVar "%d" "'$theChar"

Я обнаружил это, потому что мне нужно было создать сценарий Bash, который давал мне хэш Fowler -Noll -Vo для каждой строки текстового файла, который я цитирую здесь:

#!/bin/bash

export LC_CTYPE=C
prime=16777619                                             #FNV prime
ofset=2166136261                                           #FNV offset
mask=0xffffffff                                            #bitmask
cat $1 | while read line || [[ -n $line ]]                 #foreach line in file (w/o end return)
do
    hash=$ofset                                            #set hash to offset for line.
    for (( i=0; i<${#line}; i++ ))                         #foreach char in line
    do
        printf -v charVal "%d" "'${line:$i:1}"             #use printf -v trick.
        hash=$(( ( ( hash ^ charVal ) * prime ) & mask ))  #update FNV1-a hash for char.
    done
    printf "%08X\n" $hash                                  #print hash result for line.
done  

Использование опции -vдля назначения с помощью printfпривело к 50-кратному повышению производительности при запуске в Cygwin64.

1
09.07.2020, 20:23

Теги

Похожие вопросы