在 Bash 脚本的一开始,我传递了一组如下字符:
#!/bin/bash
set0="0 1 2 3 4 5 6 7 8 9"
set1="° § + \" ç % & / ( ) = ? ' ^ ! £ $ - _ ; , : . *"
脚本将每个字符与其他字符组合起来,以获得长度为
n
的所有可能组合。
正如您在上面的
set1
中看到的,我必须转义引号 "
字符。我现在的问题是,我也必须逃避星号*
。但我不知道怎么办。
到目前为止这还不起作用:
#!/bin/bash
set1="° § + \" ç % & / ( ) = ? ' ^ ! £ $ - _ ; , : . \*"
它回响
\*
。如果我不使用反斜杠 *
转义星号 \
,脚本将始终回显当前目录中的所有文件。
你知道我怎样才能成功逃脱星号
*
吗?
这是整个脚本:
8 chars0="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"
9 chars1="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"
10 chars2="0 1 2 3 4 5 6 7 8 9"
11 chars3="° § + \" ç % & / ( ) = ? ' ^ ! £ $ - _ ; , : . *"
12
13 function increment {
14 INPUT=$1
15 [[ ${#INPUT} -ge $minlen ]] && echo $1
16 if [[ ${#INPUT} -lt $maxlen ]]; then
17 for c in $chars; do
18 increment $1$c
19 done
20 fi
21 }
22
23 function showUsage {
24 echo "$0 MAXLEN [MINLEN] [a [A [n [p]]]]"
25 echo
26 echo " MAXLEN integer Maximum lenght, or specific lengt if MINLEN is omitted"
27 echo " MINLEN integer Minimum lenght, equals MAXLEN if omitted"
28 echo ""
29 echo " characters:"
30 echo " a lower case a-z"
31 echo " A Uppercase A-Z"
32 echo " n numeric 0-9"
33 echo " p punctuation . ?"
34 }
35
36
37
38
39 ## argument handler
40 [[ "$1" = "" ]] && showUsage && exit
41 maxlen=$1
42 [[ $2 -eq 0 ]] && minlen=$maxlen || minlen=$2
43
44
45 for arg in "$@"; do
46 case $arg in
47 a) chars="$chars $chars0" ;;
48 A) chars="$chars $chars1" ;;
49 n) chars="$chars $chars2" ;;
50 p) chars="$chars $chars3" ;;
51 esac;
52 done
53
54 #fallback
55 [[ "$chars" = "" ]] && chars="$chars0"
56
57
58
59 ## kickof
60
61 for i in $chars; do
62 increment $i
63 done
感谢您的所有建议。帮助我解决这个问题的是
set -f
这当然是一个快速解决方案。但对我来说效果很好。
最好的方法可能是使用:
set -o noglob
set="* + ?"
for i in $set; do echo $i; done
*
+
?
使用变量时的问题。
noglob
将阻止所有文件全局字符扩展。
您无法安全地循环像这样的字符串中的单词列表,而不产生令人讨厌的通配符效果。就您而言,归结为:
a=*
for i in $a; do
echo "$a"
done
您将看到当前目录中的文件被打印,因为
$a
语句中的(未加引号!恐怖!)for
扩展为 *
,它将全局显示当前目录中的文件列表。
您必须使用其他设计来解决此问题。你很幸运,Bash 很好地支持数组,所以重新设计你的代码以使用数组。例如:
chars=( ° § + \" ç % \& / '(' ')' = \? \' ^ ! £ $ - _ \; , : . \* )
(这定义了 array
chars
)并循环遍历:
for i in "${chars[@]}"; do
echo "$i"
done
(注意引号)。
下面是对代码的重写,以向您展示如何使用数组(我也修复/改进了其他一些小东西):
#!/bin/bash
chars_alpha=( {a..z} )
chars_ALPHA=( {A..Z} )
chars_digit=( {0..9} )
chars_punct=( '°' '§' '+' '"' 'ç' '%' '&' '/' '(' ')' '=' '?' "'" '^' '!' '£' '$' '-' '_' ';' ',' ':' '.' '*' )
increment() {
local input=$1
(( ${#input} >= minlen )) && printf '%s\n' "$input"
if (( ${#input} < maxlen )); then
for c in "${chars[@]}"; do
increment "$input$c"
done
fi
}
showUsage() {
cat <<EOF
$0 MAXLEN [MINLEN] [a] [A] [n] [p]
MAXLEN integer Maximum lenght, or specific lengt if MINLEN is omitted
MINLEN integer Minimum lenght, equals MAXLEN if omitted
characters:
a lower case a-z
A Uppercase A-Z
n numeric 0-9
p punctuation . ? etc.
EOF
}
## argument handler
(($#)) || { showUsage; exit 1; }
[[ $1 = +([[:digit:]]) ]] || { showUsage; exit 1; }
((maxlen=10#$1))
shift
# Check that maxlen is >0 or exit gracefully
((maxlen>0)) || exit 0
if [[ $1 = +([[:digit:]]) ]]; then
((minlen=10#$1))
shift
else
((minlen=maxlen))
fi
# Check that minlen<=maxlen otherwise swap them
if ((minlen>maxlen)); then
((temp=minlen,minlen=maxlen,maxlen=temp))
fi
chars=()
while (($#)); do
case $1 in
(a) chars+=( "${chars_alpha[@]}" ); chars_alpha=() ;;
(A) chars+=( "${chars_ALPHA[@]}" ); chars_ALPHA=() ;;
(n) chars+=( "${chars_digit[@]}" ); chars_digit=() ;;
(p) chars+=( "${chars_punct[@]}" ); chars_punct=() ;;
(*) printf >&2 'Ignored arguments %s\n' "$1" ;;
esac
shift
done
#fallback
(( ${#chars[@]} )) || chars=( "${chars_alpha[@]}" )
#kick off!
increment
其中一项修复包括使用
printf
而不是 echo
。使用 echo
,你的代码就被破坏了,因为字符串:
-e
-n
-E
永远不会被打印!请参阅
help echo
了解原因。你自己也试试吧:
echo -e
echo -n
echo -E
不输出任何内容!
使用单引号代替双引号来包裹字符串。您不必转义单引号之外的任何字符。