你的设计不是很好。你不应该像这样使用普通变量!如果你想对_、*、é等特殊字符进行编码,就会遇到问题。
相反,您应该使用关联数组。这是一个完整的纯 Bash 工作示例:
#!/bin/bash
# read message to encode on stdin and outputs message to stdout
declare -A lookup
lookup=(
[a]=n [b]=o [c]=p [d]=q [e]=r [f]=s [g]=t [h]=u [i]=v [j]=w [k]=x
[l]=y [m]=z [n]=a [o]=b [p]=c [q]=d [r]=e [s]=f [t]=g [u]=h [v]=i
[w]=j [x]=k [y]=l [z]=m
)
while IFS= read -r -d '' -n 1 char; do
if [[ -z $char ]]; then
# null byte
printf '\0'
elif [[ ${lookup["$char"]} ]]; then
# defined character
printf '%s' "${lookup["$char"]}"
elif [[ $char = @(' '|$'\n') ]]; then
# space and newline
printf '%s' "$char"
else
# other characters passed verbatim with warning message
printf >&2 "Warning, character \`%s' not supported\n" "$char"
printf '%s' "$char"
fi
done
我将此脚本称为 banana、chmod +x banana 和:
$ ./banana <<< "hello stackoverflow"
uryyb fgnpxbiresybj
$ ./banana <<< "uryyb fgnpxbiresybj"
hello stackoverflow
如果要对变量input的内容进行编码,并将编码后的文本存储在变量output中,只需将主循环修改为:
output=
linput=$input
while [[ $linput ]]; do
char=${linput::1}
linput=${linput:1}
if [[ ${lookup["$char"]} ]]; then
# defined character
output+=${lookup["$char"]}
elif [[ $char = @(' '|$'\n') ]]; then
# space and newline
output+=$char
else
# other characters passed verbatim with warning message
printf >&2 "Warning, character \`%s' not supported\n" "$char"
output+=$char
fi
done
在这种情况下,我省略了对空字节的检查,因为 Bash 变量不能包含空字节。
这样进行,您可以真正编码任何您喜欢的字符(甚至是空字节 - 在第一个版本中 - 和换行符)。
编辑(重新发表您的评论)。
您想将此用于Caesar cipher 脚本。您担心的是您提示用户输入用于轮班的号码,并且您不知道如何在您的情况下使用此方法。关键是查找表的生成比较容易。
这是一个完整的示例:
#!/bin/bash
chrv() {
local c
printf -v c '\\%03o' "$1"
printf -v "$2" "$c"
}
ansi_normal=$'\E[0m'
ansi_lightgreen=$'\E[02m'
while true; do
printf '%s' "Encryption key (number from ${ansi_lightgreen}1$ansi_normal to ${ansi_lightgreen}26$ansi_normal): "
read -re ekey
if [[ $ekey = +([[:digit:]]) ]]; then
((ekey=10#$ekey))
((ekey>=1 && ekey<=26)) && break
fi
printf 'Bad number. Try again.\n'
done
# Build the lookup table according to this number
declare -A lookup
for i in {0..25}; do
for u in 65 97; do
chrv "$((i+u))" basechar
chrv "$(((i+ekey-1)%26+u))" "lookup["$basechar"]"
done
done
printf '%s' "Input (only ${ansi_lightgreen}letters$ansi_normal and ${ansi_lightgreen}spaces${ansi_normal}): "
IFS= read -re einput
read -n1 -rep "Do you want output to be uppercase? ${ansi_lightgreen}(y/n)$ansi_normal " oup
[[ ${oup,,} = y ]] && einput=${einput^^}
output=
linput=$einput
while [[ $linput ]]; do
char=${linput::1}
linput=${linput:1}
if [[ ${lookup["$char"]} ]]; then
# defined character
output+=${lookup["$char"]}
elif [[ $char = @(' '|$'\n') ]]; then
# space and newline
output+=$char
else
# other characters passed verbatim with warning message
printf >&2 "Warning, character \`%s' not supported\n" "$char"
output+=$char
fi
done
printf 'Original text: %s\n' "$einput"
printf 'Encoded text: %s\n' "$output"
纯 Bash,没有子 shell :)。