试图做类似rot13的解决方案,可以处理特殊的字符

时间:2014-05-24 01:08:24

标签: bash sed tr

我想在rot13函数上实现一个使用随机生成的alpha-num键的功能,但我也希望包含特殊字符,但似乎无法使用它。使用包含特殊字符的tr命令的此函数不起作用:

echo "$@" | tr "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789!@#$%^&*()-_=+\|" "A*KWx#o(5I-j\e|Hv)X7R0SJ=8+tBE^ucOVgMd2l$QkafU4nqz36LPhGb1rmswi%FC@!D_p9N&YyZT"

所以我编写了一个更复杂的函数,将一个单词的字母拆分成一个数组,然后通过for循环传递每个数组元素,该循环由92个if / elif语句组成,当时char是匹配然后运行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

它现在有效,但并不完全。我需要输入用单引号括起来的转换输入字,因为看起来有特殊的字符处理(很多试验和错误来计算出那个!),除了如何输入要转换的单词外,这一切都很好如果它包含单引号char?

最终我更愿意使用更简单的解决方案,例如使用tr命令,如果有人建议如何使用tr来管理特殊字符,这将是很好的。如果没有,那么如果输入似乎需要用单引号括起来,如何输入包含特殊字符的单词,包括单引号?

可能是Unicodes吗?但这听起来比我现有的解决方案更加丑陋。

其他信息: Hey Gene感谢您的快速回复。它几乎就在那里,比我管理的要多得多。我完全忘记了破折号,但我通常只考虑那些用方括号括起来的东西,记住它们需要是指定的最后一个字符,以避免定义不需要的范围。

在第二个(已翻译的)字符集中的第一个转义字符后面的所有翻译字母,短划线-,都会添加一个偏移量;并且在该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
我错误地用x引用了&#34; e&#34;而不是&#34; 3&#34;,所以请:

|GiPL fp9VJo

全部出两个地方。我可能会掀起一个黑客来计算逃脱的角色并相应地进行调整,但似乎奇怪的是,加入特殊的角色应该是如此难以理解。我甚至试图将它们放入数组元素中,这也不是一个糟糕的方法,但是也可以反复讨论它。

我一直在使用电子表格使char x-references尽可能简单。但在这里他们是并排的:

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

更多信息:所以我去了另一个,可能效率更低的方式,但现在一切都工作得很好;除了仍然没有办法输入包含单引号和dbl引号的字符串,所以除非有一种我尚未找到的方法,否则在使用以下脚本时我必须记住这个限制: / p>

# 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的结果,如果可以使用更简单的解决方案,写信比包括我会使用的特殊字符,但是我所有尝试获得{{1正确映射我没有成功。也许我只是看着并编辑相同的命令太长时间以及太多次看到简单的解决方案。

2 个答案:

答案 0 :(得分:3)

问题首先是您需要围绕tr参数的单引号,以防止bash在字符串中展开$。此外,你忘了tr特别对待几个角色:

  • 短划线-创建字符集。
  • 反斜杠会逃脱后面的任何内容。

这可以通过反斜杠转义破折号和反斜杠来解决这些问题。

tr 'aAbBcCdDeEFGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789!@#$%^&*()\-_=+\\|' \
   'A*KWx#o(5I\-j\\e|Hv)X7R0SJ=8+tBE^ucOVgMd2l$QkafU4nqz36LPhGb1rmswi%FC@!D_p9&YyT' 

我的mingw bash工作正常。

您没有使用方括号[,但如果您将来这样做,请注意这些也会导致问题,如果没有转义的话。

<强>加成

解决OP的断言,这是不正确的,我看不出如何。使用上面的转义字符串但删除反斜杠以显示等价:

Plain:  aAbBcCdDeEFGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789!@#$%^&*()-_=+\|
Cypher: A*KWx#o(5I-j\e|Hv)X7R0SJ=8+tBE^ucOVgMd2l$QkafU4nqz36LPhGb1rmswi%FC@!D_p9&YyT

手工翻译:

h3!10 w()rLd
\Ps63 kD_c0o

然而OP的“应该是”字符串是不同的。也许我不明白我们想要完成什么。

实施OP的新表

您的新表格不是tr命令行中的新表格。这是相应的翻译(我从一个带有您的表作为输入的小Ruby脚本中获得):

Plain:  aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789!@#$%^&*()-_=+|\
Cypher: A*KWx#o(5I-j\e|Hv)X7R0SJ=8+tBE^ucOVgMd2l$QkafU4nqz36LPhGb1rmswi%FC@!D_p9N&YyZT

请注意,这只是水平显示的表格。没什么好看的。

添加了反斜杠转义的结果tr命令只是

echo 'h3!10 w()rLd' | \
tr 'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789!@#$%^&*()\-_=+|\\' \
   'A*KWx#o(5I\-j\\e|Hv)X7R0SJ=8+tBE^ucOVgMd2l$QkafU4nqz36LPhGb1rmswi%FC@!D_p9N&YyZT'

在我的包装盒上打印:

|GiPL fp9VJo

或者将参数切换到另一个方向(因为您的密码不对称)。

echo '|GiPL fp9VJo' | \
tr 'A*KWx#o(5I\-j\\e|Hv)X7R0SJ=8+tBE^ucOVgMd2l$QkafU4nqz36LPhGb1rmswi%FC@!D_p9N&YyZT' \
   'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789!@#$%^&*()\-_=+|\\'

这会产生

h3!10 w()rLd

在我的盒子上,就像你期望的那样。

答案 1 :(得分:1)

使用'tr'的原始解决方案存在两个问题:

  1. 您使用的是双引号,但内部有一个$,这对shell来说很特殊。
  2. 您的翻译不对称:a被翻译为A,但A被翻译为*。
  3. 我可能会用sed -e'y ///'(或者python)来做这件事,但tr的一个优点是你可以使用字符集:

    tr '[:upper:][:lower:]' '[:lower:][:upper:]'
    

    但无论哪种方式,你都必须自己列出特殊字符对。