文件夹中字符输出文件列表中的转义星号 (*)

Escaped asterisk (*) in list of characters outputs file in folder

在我的 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=
 15         [[ ${#INPUT} -ge $minlen ]]  && echo 
 16         if [[ ${#INPUT} -lt $maxlen ]]; then
 17                 for c in $chars; do
 18                         increment $c
 19                 done
 20         fi
 21 }
 22 
 23 function showUsage {
 24         echo "[=12=] 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 [[ "" = "" ]] && showUsage && exit
 41 maxlen=
 42 [[  -eq 0 ]] && minlen=$maxlen || minlen=
 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 -o noglob
set="* + ?"
for i in $set; do echo $i; done
*
+
?

使用变量时的问题。 noglob 将阻止所有文件 glob 字符扩展。

你不能安全地循环像这样的字符串中的单词列表,而不会产生令人讨厌的通配效果。在你的情况下,它归结为:

a=*
for i in $a; do
    echo "$a"
done

您会看到当前目录中的文件已打印出来,因为 for 语句中的(未加引号!恐怖!)$a 扩展为 *,这将导致 glob到当前目录中的文件列表。

您必须使用其他设计来解决此问题。你很幸运,Bash 很好地支持数组,所以重新设计你的代码以使用数组。例如:

chars=( ° § + \" ç % \& / '(' ')' = \? \' ^ ! £ $ - _ \; , : . \* )

(这定义了 数组 chars)并循环遍历:

for i in "${chars[@]}"; do
    echo "$i"
done

(注意引号)。


下面是对您的代码的重写,以向您展示如何使用数组(我还 fixed/improved 一些其他的小东西):

#!/bin/bash

chars_alpha=( {a..z} )
chars_ALPHA=( {A..Z} )
chars_digit=( {0..9} )
chars_punct=( '°' '§' '+' '"' 'ç' '%' '&' '/' '(' ')' '=' '?' "'" '^' '!' '£' '$' '-' '_' ';' ',' ':' '.' '*' )

increment() {
   local input=
   (( ${#input} >= minlen )) && printf '%s\n' "$input"
   if (( ${#input} < maxlen )); then
      for c in "${chars[@]}"; do
         increment "$input$c"
      done
   fi
}

showUsage() {
   cat <<EOF
[=13=] 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; }

[[  = +([[:digit:]]) ]] || { showUsage; exit 1; }
((maxlen=10#))
shift

# Check that maxlen is >0 or exit gracefully
((maxlen>0)) || exit 0

if [[  = +([[:digit:]]) ]]; then
   ((minlen=10#))
   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  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' "" ;;
    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

不要输出任何东西!

感谢您的所有建议。帮助我解决这个问题的是

set -f

这当然是一个快速修复。但对我来说效果很好。