Bash-使用通配符元素创建一个数组以进行匹配

时间:2018-09-22 06:13:34

标签: bash syntax sh

我想创建一个如下数组,以检查输出文件名是否与数组中的模式匹配。

declare -a arr=('class*_1n_*000000.txt','class*_1n_*010000.txt','class*_2n_*010000.txt','class*_2n_*012000.txt','class*_3n_*235000.txt')

if [[ "${arr[*]}"==$output_filename ]]; then
   echo $output_filename exist in arr
   #do something...
else
   echo $output_filename not exist in arr
   #do something...
fi

我已经尝试了以下3个案例,而评论将是我的预期结果

output_filename='class_2n_20180922012000.txt' #exist
output_filename='classA_2n_20180923012000.txt' #exist
output_filename='classA_4n_20180923012000.txt' #not exist

但所有三种情况都存在。

如何解决此问题?

任何帮助将不胜感激:)

1 个答案:

答案 0 :(得分:1)

好的,首先让我们解决几个基本的shell语法问题。数组声明:

declare -a arr=('class*_1n_*000000.txt','class*_1n_*010000.txt','class*_2n_*010000.txt','class*_2n_*012000.txt','class*_3n_*235000.txt')

不起作用,因为bash不使用逗号分隔数组的元素,而是使用空格。由于那里没有空格,因此外壳程序会将其视为一个大数组元素,其中恰好包含一些逗号。您想要这个:

declare -a arr=('class*_1n_*000000.txt' 'class*_1n_*010000.txt' 'class*_2n_*010000.txt' 'class*_2n_*012000.txt' 'class*_3n_*235000.txt')

第二,比较:

if [[ "${arr[*]}"==$output_filename ]]; then

根本没有做任何您想做的事情。同样,空格是shell语法中的定界符,并且由于周围没有空格,==不会被视为运算符,因此它只是单个长字符串的一部分。 [[ somestring ]]进行测试以查看字符串是否为非空白,并且由于该字符串不是空白,因此测试始终以true表示。现在,明显的解决方法是:

if [[ "${arr[*]}" == $output_filename ]]; then

...至少进行比较,但不进行所需的比较。它将数组的整个内容(所有元素之间都留有空格,因为[*]就是这样)视为单个字符串,并查看它是否与$output_filename匹配,其中$output_filename被视为通配符模式。但您希望将数组元素视为通配符模式,因此需要将其反转:

if [[ "$output_filename" == ${arr[*]} ]]; then

...但这不是您想要的 ,因为它正在检查$output_filename是否与arr中所有条目的 all 相匹配粘在一起。为了使其匹配,$output_filename必须是由五个文件名组成的列表,并用空格分隔,第一个匹配的class*_1n_*000000.txt,第二个匹配的class*_1n_*010000.txt等。您需要一次将文件名与每个数组元素进行比较,并跟踪是否找到匹配项。像这样:

found_match="false"
for pattern in "${arr[@]}"; do
    if [[ "$output_filename" == $pattern ]]; then
        found_match="true"
        break
    fi
done
if [[ "$found_match" == true ]]; then
   echo "$output_filename exist in arr"
   #do something...
else
   echo "$output_filename not exist in arr"
   #do something...
fi

请注意,"${arr[@]}"(注意双引号和@)扩展到数组的每个元素,每个元素都被视为一个单独的字符串(因此for会在它们上进行迭代) 。另外,我在要打印的字符串两边加上了双引号。您几乎总是希望在变量引用(或包含变量引用的内容)两边加上双引号,以避免意外的通配符扩展等。但是,这里有一个例外:在[[ "$output_filename" == $pattern ]]中,$pattern必须保留不带引号,以便将其视为通配符模式而不是固定字符串。