Bash 检测没有相应变量的字符
Bash detect characters that don't have corresponding var
我已经编写了一个脚本,它为每个字母定义了一个变量(用于加密过程),但我希望输出中有空格。
我有这个:
eiput_splitted="$(echo $einput | sed -e 's/\(.\)/\n/g')"
export eouput=""
for input in $eiput_splitted; do
export eouput=$eouput${!input}
//added code here
done
但我不知道如何检测循环中的空格。
我试过了
if [ $input = \ ]
if [ $input = *\ * ]
if [ $input = *"\ "* ]
if [ $input = "*\ *" ]
if [ -z ${!input+x} ] (to detect unset variables, but doesn't seem to work..)
你能帮帮我吗?
使用 IFS=$'\n'
.
将内部字段分隔符从空格更改为换行符
您可以在 BASH 中使用它:
while IFS= read -r ch; do
[[ "$ch" == " " ]] && echo "space character"
done < <(grep -o . <<< "$einput")
grep -o . <<< "$einput"
逐字符拆分输入字符串
< <(...)
称为进程替换
IFS=
将输入字段分隔符设置为空(以允许 space 被 `read 读取)
因为您没有引用字符串,所以其中的任何空格都将丢失。试试这个。
echo "$einput" |
sed -e 's/\(.\)/\n/g' |
while IFS= read -r input; do
eouput="$eouput${!input}"
:
done
根据您的进一步处理情况,我可能只是 printf '%s' "${!input}"
在循环内,并在必要时在 done
之后在管道中处理其输出,以避免另一个变量。
要遍历字符串的字符,可以使用参数扩展:
eiput='Hello World!'
H="capital letter 'h'"
l="I appear 3 times"
strlen=${#eiput}
for ((i=0; i<strlen; i++)); do
char=${eiput:i:1}
printf "%2d:%c:%s\n" $i "$char" "${!char}"
done
0:H:capital letter 'h'
1:e:
2:l:I appear 3 times
3:l:I appear 3 times
4:o:
5: :
6:W:
7:o:
8:r:
9:l:I appear 3 times
10:d:
11:!:
你的设计不是很好。你不应该像这样使用普通变量!如果你想编码像 _
、*
、é
等特殊字符,你会 运行 遇到问题
相反,您应该使用关联数组。这是一个完整的 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 '[=10=]'
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 Whosebug"
uryyb fgnpxbiresybj
$ ./banana <<< "uryyb fgnpxbiresybj"
hello Whosebug
如果要对变量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 脚本。您担心的是您提示用户输入用于轮班的号码,而您不知道如何在您的情况下使用此方法。关键是生成查找 table.
相当容易
这是一个完整的示例:
#!/bin/bash
chrv() {
local c
printf -v c '\%03o' ""
printf -v "" "$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 且无子壳 :)
。
我已经编写了一个脚本,它为每个字母定义了一个变量(用于加密过程),但我希望输出中有空格。
我有这个:
eiput_splitted="$(echo $einput | sed -e 's/\(.\)/\n/g')"
export eouput=""
for input in $eiput_splitted; do
export eouput=$eouput${!input}
//added code here
done
但我不知道如何检测循环中的空格。 我试过了
if [ $input = \ ]
if [ $input = *\ * ]
if [ $input = *"\ "* ]
if [ $input = "*\ *" ]
if [ -z ${!input+x} ] (to detect unset variables, but doesn't seem to work..)
你能帮帮我吗?
使用 IFS=$'\n'
.
您可以在 BASH 中使用它:
while IFS= read -r ch; do
[[ "$ch" == " " ]] && echo "space character"
done < <(grep -o . <<< "$einput")
grep -o . <<< "$einput"
逐字符拆分输入字符串< <(...)
称为进程替换IFS=
将输入字段分隔符设置为空(以允许 space 被 `read 读取)
因为您没有引用字符串,所以其中的任何空格都将丢失。试试这个。
echo "$einput" |
sed -e 's/\(.\)/\n/g' |
while IFS= read -r input; do
eouput="$eouput${!input}"
:
done
根据您的进一步处理情况,我可能只是 printf '%s' "${!input}"
在循环内,并在必要时在 done
之后在管道中处理其输出,以避免另一个变量。
要遍历字符串的字符,可以使用参数扩展:
eiput='Hello World!'
H="capital letter 'h'"
l="I appear 3 times"
strlen=${#eiput}
for ((i=0; i<strlen; i++)); do
char=${eiput:i:1}
printf "%2d:%c:%s\n" $i "$char" "${!char}"
done
0:H:capital letter 'h'
1:e:
2:l:I appear 3 times
3:l:I appear 3 times
4:o:
5: :
6:W:
7:o:
8:r:
9:l:I appear 3 times
10:d:
11:!:
你的设计不是很好。你不应该像这样使用普通变量!如果你想编码像 _
、*
、é
等特殊字符,你会 运行 遇到问题
相反,您应该使用关联数组。这是一个完整的 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 '[=10=]'
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 Whosebug"
uryyb fgnpxbiresybj
$ ./banana <<< "uryyb fgnpxbiresybj"
hello Whosebug
如果要对变量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 脚本。您担心的是您提示用户输入用于轮班的号码,而您不知道如何在您的情况下使用此方法。关键是生成查找 table.
相当容易这是一个完整的示例:
#!/bin/bash
chrv() {
local c
printf -v c '\%03o' ""
printf -v "" "$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 且无子壳 :)
。