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

时间:2015-02-28 18:40:37

标签: bash shell escaping asterisk

在我的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

4 个答案:

答案 0 :(得分:0)

最好的方法是使用:

set -o noglob
set="* + ?"
for i in $set; do echo $i; done
*
+
?

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

答案 1 :(得分:0)

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

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

你会看到当前目录中的文件被打印出来,因为$a语句中的(未引用的!恐怖!)for会扩展为*当前目录中的文件列表。

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

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

(这定义了数组 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

不输出任何内容!

答案 2 :(得分:0)

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

set -f

当然,这是一个快速解决方案。但它对我来说效果很好。

答案 3 :(得分:-1)

使用单引号包装字符串而不是双引号。您不必在单引号旁边转义任何字符。