Я хочу реализовать функцию rot13, которая использует случайно сгенерированные буквенно-цифровые клавиши, но я также хочу включить специальные символы и, похоже, не могу заставить это работать. Эта функция с использованием команды tr
, включая специальные символы, не работает:
echo "$@" | tr "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789!@#$%^&*()-_=+\|" "A*KWx#o(5I-j\e|Hv)X7R0SJ=8+tBE^ucOVgMd2l$QkafU4nqz36LPhGb1rmswi%FC@!D_p9N&YyZT"
Поэтому я написал гораздо более запутанную функцию, которая разбивает буквы слова на массив, а затем передает каждый элемент массива через цикл for
, состоящий из 92 операторов if/elif, которые при совпадении символа запускают подпрограмму замены sed
:
conv=""
x="$1" ; echo "\$1: ${1}"
i=0
while [ $i -lt ${#x} ]; do y[$i]=${x:$i:1}; i=$((i+1));done
for f in "${y[@]}" ; do
newF=$(echo "$f"|if [[ "$f" == "a" ]] ; then sed -r 's/a/7/g' ; elif [[ "$f" == "A" ]] ; then sed -r 's/A/\?/g' ; elif [[ "$f" == "b" ]] ; then sed -r 's/b/v/g' ; elif [[ "$f" == "B" ]] ; then sed -r 's/B/\./g' ; elif [[ "$f" == "c" ]] ; then sed -r 's/c/q/g' ; elif [[ "$f" == "C" ]] ; then sed -r 's/C/2/g' ; elif [[ "$f" == "d" ]] ; then sed -r 's/d/m/g' ; elif [[ "$f" == "D" ]] ; then sed -r 's/D/\Z/g' ; elif [[ "$f" == "e" ]] ; then sed -r 's/e/S/g' ; elif [[ "$f" == "E" ]] ; then sed -r 's/E/y/g' ; elif [[ "$f" == "f" ]] ; then sed -r 's/f/d/g' ; elif [[ "$f" == "F" ]] ; then sed -r 's/F/\)/g' ; elif [[ "$f" == "g" ]] ; then sed -r 's/g/z/g' ; elif [[ "$f" == "G" ]] ; then sed -r 's/G/K/g' ; elif [[ "$f" == "h" ]] ; then sed -r 's/h/T/g' ; elif [[ "$f" == "H" ]] ; then sed -r 's/H/\{/g' ; elif [[ "$f" == "i" ]] ; then sed -r 's/i/8/g' ; elif [[ "$f" == "I" ]] ; then sed -r 's/I/H/g' ; elif [[ "$f" == "j" ]] ; then sed -r 's/j/p/g' ; elif [[ "$f" == "J" ]] ; then sed -r 's/J/A/g' ; elif [[ "$f" == "k" ]] ; then sed -r 's/k/@/g' ; elif [[ "$f" == "K" ]] ; then sed -r 's/K/R/g' ; elif [[ "$f" == "l" ]] ; then sed -r 's/l/W/g' ; elif [[ "$f" == "L" ]] ; then sed -r 's/L/9/g' ; elif [[ "$f" == "m" ]] ; then sed -r 's/m/s/g' ; elif [[ "$f" == "M" ]] ; then sed -r 's/M/\(/g' ; elif [[ "$f" == "n" ]] ; then sed -r 's/n/V/g' ; elif [[ "$f" == "N" ]] ; then sed -r 's/N/t/g' ; elif [[ "$f" == "o" ]] ; then sed -r 's/o/\\/g' ; elif [[ "$f" == "O" ]] ; then sed -r 's/O/\!/g' ; elif [[ "$f" == "p" ]] ; then sed -r 's/p/=/g' ; elif [[ "$f" == "P" ]] ; then sed -r 's/P/n/g' ; elif [[ "$f" == "q" ]] ; then sed -r 's/q/#/g' ; elif [[ "$f" == "Q" ]] ; then sed -r 's/Q/e/g' ; elif [[ "$f" == "r" ]] ; then sed -r 's/r/g/g' ; elif [[ "$f" == "R" ]] ; then sed -r 's/R/f/g' ; elif [[ "$f" == "s" ]] ; then sed -r 's/s/-/g' ; elif [[ "$f" == "S" ]] ; then sed -r 's/S/0/g' ; elif [[ "$f" == "t" ]] ; then sed -r 's/t/,/g' ; elif [[ "$f" == "T" ]] ; then sed -r 's/T/:/g' ; elif [[ "$f" == "u" ]] ; then sed -r 's/u/_/g' ; elif [[ "$f" == "U" ]] ; then sed -r 's/U/Q/g' ; elif [[ "$f" == "v" ]] ; then sed -r 's/v/i/g' ; elif [[ "$f" == "V" ]] ; then sed -r 's/V/k/g' ; elif [[ "$f" == "w" ]] ; then sed -r 's/w/w/g' ; elif [[ "$f" == "W" ]] ; then sed -r 's/W/l/g' ; elif [[ "$f" == "x" ]] ; then sed -r 's/x/3/g' ; elif [[ "$f" == "X" ]] ; then sed -r 's/X/\]/g' ; elif [[ "$f" == "y" ]] ; then sed -r 's/y/5/g' ; elif [[ "$f" == "Y" ]] ; then sed -r 's/Y/O/g' ; elif [[ "$f" == "z" ]] ; then sed -r 's/z/F/g' ; elif [[ "$f" == "Z" ]] ; then sed -r 's/Z/"/g' ; elif [[ "$f" == "0" ]] ; then sed -r 's/0/;/g' ; elif [[ "$f" == "1" ]] ; then sed -r 's/1/E/g' ; elif [[ "$f" == "2" ]] ; then sed -r 's/2/>/g' ; elif [[ "$f" == "3" ]] ; then sed -r 's/3/u/g' ; elif [[ "$f" == "4" ]] ; then sed -r 's/4/\$/g' ; elif [[ "$f" == "5" ]] ; then sed -r 's/5/</g' ; elif [[ "$f" == "6" ]] ; then sed -r 's/6/\+/g' ; elif [[ "$f" == "7" ]] ; then sed -r 's/7/x/g' ; elif [[ "$f" == "8" ]] ; then sed -r 's/8/L/g' ; elif [[ "$f" == "9" ]] ; then sed -r 's/9/C/g' ; elif [[ "$f" == "!" ]] ; then sed -r 's/\!/a/g' ; elif [[ "$f" == "@" ]] ; then sed -r 's/@/\//g' ; elif [[ "$f" == "#" ]] ; then sed -r 's/#/M/g' ; elif [[ "$f" == "$" ]] ; then sed -r "s/\$/'/g" ; elif [[ "$f" == "%" ]] ; then sed -r 's/%/1/g' ; elif [[ "$f" == "^" ]] ; then sed -r 's/\^/c/g' ; elif [[ "$f" == "&" ]] ; then sed -r 's/\&/h/g' ; elif [[ "$f" == "*" ]] ; then sed -r 's/\*/U/g' ; elif [[ "$f" == "(" ]] ; then sed -r 's/\(/\|/g' ; elif [[ "$f" == ")" ]] ; then sed -r 's/\)/\[/g' ; elif [[ "$f" == "-" ]] ; then sed -r 's/-/I/g' ; elif [[ "$f" == "_" ]] ; then sed -r 's/_/\*/g' ; elif [[ "$f" == "=" ]] ; then sed -r 's/=/G/g' ; elif [[ "$f" == "+" ]] ; then sed -r 's/\+/P/g' ; elif [[ "$f" == "|" ]] ; then sed -r 's/\|/o/g' ; elif [[ "$f" == '\' ]] ; then sed -r 's/\\/Y/g' ; elif [[ "$f" == "[" ]] ; then sed -r 's/\[/j/g' ; elif [[ "$f" == "{" ]] ; then sed -r 's/\{/B/g' ; elif [[ "$f" == "]" ]] ; then sed -r 's/\]/\%/g' ; elif [[ "$f" == "}" ]] ; then sed -r 's/\}/J/g' ; elif [[ "$f" == ";" ]] ; then sed -r 's/;/X/g' ; elif [[ "$f" == ":" ]] ; then sed -r 's/:/\^/g' ; elif [[ "$f" == "'" ]] ; then sed -r "s/'/D/g"; elif [[ "$f" == '"' ]] ; then sed -r 's/"/\}/g' ; elif [[ "$f" == "," ]] ; then sed -r 's/,/4/g' ; elif [[ "$f" == "<" ]] ; then sed -r 's/</r/g' ; elif [[ "$f" == "." ]] ; then sed -r 's/\./N/g' ; elif [[ "$f" == ">" ]] ; then sed -r 's/>/\&/g' ; elif [[ "$f" == "/" ]] ; then sed -r 's/\//6/g' ; elif [[ "$f" == "?" ]] ; then sed -r 's/\?/b/g' ; fi)
echo "converting: $f to $newF"
conv="${conv}${newF}" ; echo "\$conv: ${conv}"
done
Сейчас вроде работает, но не совсем. Мне нужно ввести входные слова для преобразования, заключенные в одинарные кавычки, из-за специальной обработки символов, кажется (много проб и ошибок, чтобы понять это!), Что все в порядке, кроме как ввести слово для преобразования если он содержит символ одинарной кавычки?
В конечном счете, я бы предпочел использовать более простое решение, такое как команда tr
, если у кого-нибудь есть совет, как управлять специальными символами с помощью tr
, это было бы здорово. Если нет, то как я могу ввести слово, содержащее специальные символы, включая одинарную кавычку, если кажется, что ввод должен быть заключен в одинарные кавычки?
Может юникоды? Но это звучит как еще более уродливое решение, чем то, что у меня уже есть.
Дополнительная информация: Привет, Джин, спасибо за быстрые ответы. Это почти там, намного дальше, чем мне удалось. Я полностью забыл о тире, но обычно я думаю о них только тогда, когда заключаю их в квадратные скобки, помня, что они должны быть последними указанными символами, чтобы избежать определения нежелательного диапазона.
Все переведенные буквы, идущие после первого экранированного символа во втором (переведенном) наборе символов, тире -
добавляют смещение; и каждый последующий экранированный после этого char добавляет еще одно смещение к результату. Таким образом, для:
$ echo 'h3!10 w()rLd'|tr 'aAbBcCdDeEFGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789!@#$%^&*()\-_=+\\|' 'A*KWx#o(5I\-j\\e|Hv)X7R0SJ=8+tBE^ucOVgMd2l$QkafU4nqz36LPhGb1rmswi%FC@!D_p9&YyT'
результат:
\Ps63 kD_c0o
но должно быть:
|5iPL fp9VJo
Я по ошибке указал "е" вместо "3", так что сделайте так:
|GiPL fp9VJo
Все на два места. Вероятно, я мог бы придумать хак, чтобы вычислить экранированные символы и соответствующим образом настроить, но кажется странным, что включение специальных символов должно быть настолько сложным. Я даже пытался поместить их в элементы массива, что тоже было бы неплохо, но bash отказывается от этого.
Я использовал электронную таблицу, чтобы сделать X-ссылки на символы как можно проще. Но вот они рядом:
a <=> A n <=> + 0 <=> L
A <=> * N <=> t 1 <=> P
b <=> K o <=> B 2 <=> h
B <=> W O <=> E 3 <=> G
c <=> x p <=> ^ 4 <=> b
C <=> # P <=> u 5 <=> 1
d <=> o q <=> c 6 <=> r
D <=> ( Q <=> O 7 <=> m
e <=> 5 r <=> V 8 <=> s
E <=> I R <=> g 9 <=> w
f <=> - s <=> M ! <=> i
F <=> j S <=> d @ <=> %
g <=> \ t <=> 2 # <=> F
G <=> e T <=> l $ <=> C
h <=> | u <=> $ % <=> @
H <=> H U <=> Q ^ <=> !
i <=> v v <=> k & <=> D
I <=> ) V <=> a * <=> _
j <=> X w <=> f ( <=> p
J <=> 7 W <=> U ) <=> 9
k <=> R x <=> 4 - <=> N
K <=> 0 X <=> n _ <=> &
l <=> S y <=> q = <=> Y
L <=> J Y <=> z + <=> y
m <=> = z <=> 3 | <=> Z
M <=> 8 Z <=> 6 \ <=> T
Еще больше информации: поэтому я пошел другим, возможно, более неэффективным путем, но теперь все работает нормально; за исключением того, что по-прежнему нет способа ввести строку, содержащую как одинарные, так и двойные кавычки, поэтому, если нет способа обойти то, что я еще не нашел, мне просто нужно помнить об этом ограничении при использовании следующий сценарий:
# array containing regular alphaNumSpecChar
abc=(a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 '!' '@' '#' '$' '%' '^' '&' '*' '(' ')' '-' '_' '=' '+' '|' '\' '[' '{' ']' '}' ';' ':' "'" '"' ',' '.' '/' '?' '<' '>') #; echo "${#abc[@]}"
# randomly generated array key to cross-reference array elements in "$abc[@]}", so that if user input charater being processed is "b", "${abc[1]}" then the value for "${ranNum[2]}", 41 is used to convert "b" to "${abc[41]}", which is "P"
ranNum=(40 41 47 52 1 68 20 54 17 2 59 13 11 57 90 33 82 4 31 70 29 26 83 63 56 38 28 61 25 32 49 43 23 45 64 55 9 69 44 60 91 5 84 88 22 14 62 87 7 86 39 78 48 46 58 73 3 6 16 8 37 72 74 67 80 35 77 66 89 53 12 79 42 27 21 18 65 0 75 85 34 10 15 19 76 50 51 71 81 36 24 30)
# var for conversion result
convRes=""
# while loop to map user's input string's individual chars to array 'y'
x="$1" #; echo "\$1: ${1}"
i=0
while [ $i -lt ${#x} ]; do
y[$i]=${x:$i:1}
i=$((i+1))
done
for f in "${y[@]}" ; do # for loop to process each array element from user's input string
cntr1=0
while [[ "$cntr" -le "${#abc[@]}" ]] ; do # while loop to cycle thru all elements in array "${abc[@]}" to figure out what char it is
if [[ "$f" == "${abc[$cntr1]}" ]] ; then #'if' user input char is matched then using value of "$cntr1" var cross reference applicable random char conversion number
convNum="${ranNum[$cntr1]}" #; echo "\$convNum: ${convNum}"
#echo "converting: $f to $convNum"
# append current converted char to $convRes var
convRes="${convRes}${abc[$convNum]}" #; echo "\$convRes: ${convRes}"
break
fi
((cntr1++))
done
done
echo -e "\n\$convRes: ${convRes}\n"
Итак, если пользователь вводит:
$ rotateRandom.sh 'h3!1()W0rLd'
скрипт возвращает:
$convRes: 2_b@m{hWe*0
Результат, на который я изначально надеялся использовать tr
, и если бы его можно было получить, используя это гораздо более простое решение, буква за буквой, чем включает специальные символы, я бы использовал его, но все мои попытки заставить tr
правильно отображать я не увенчались успехом. Может быть, я просто просматривал и редактировал одну и ту же команду слишком долго и слишком много раз, чтобы увидеть простое решение.
tr
. В противном случае вы должны экранировать специальные символы с помощью обратной косой черты. Вы сделали это в других строках! Командаtr
будет работать нормально, если вы укажете правильные аргументы. - person Gene   schedule 24.05.2014tr
, который я включил, и запустить в cli, чтобы посмотреть, работает ли он у вас? - person nanker   schedule 24.05.2014