字符串变量中的通配符扩展

3
我正在从黑名单文件中读取字符串,其中包含应该被删除的文件和文件夹。对于简单的文件名,它可以正常工作,但是对于通配符则不行。
例如,如果我在shell中输入rm -rf !(abc|def),它会删除除这两个文件以外的所有文件。但是,当将此字符串!(abc|def)放入黑名单中时,它无法正常工作,因为该字符串没有被评估。
所以我尝试使用eval,但它并没有按预期工作。
#!/bin/bash
# test pattern (normally read from blacklist file)
LINE="!(abc|def)"

# output string
echo "$LINE"

# try to expand this wildcards
eval "ls $LINE"

# try with subshell
( ls $LINE )

我该如何使其工作?

我正在从黑名单文件中读取字符串:如何实现?你的代码没有展示这部分。 - sjsam
对于这个问题,最好使用带有-regex和-delete的find命令。 - Raman Sailopal
sjsam,我没展示这个部分是因为它与我的问题无关。我准备了一个简化版的脚本,以便更容易地重现问题。 - user3150128
1个回答

5

很可能对于非交互式shell(例如脚本运行的那个)extglob shell选项已经关闭了。

您需要做一些更改:

#!/bin/bash

# Turn on extglob shell option
shopt -s extglob

line='!(abc|def)'

echo "$line"

# Quoting suppresses glob expansion; this will not work
ls "$line"

# Unquoted: works!
ls $line

您需要执行以下操作:

  • 打开 extglob shell 选项
  • 不要对 $line 进行引号包裹:引号包裹会抑制通配符扩展,这在大多数情况下都是期望的,但这里不是

请注意,我使用小写变量名。大写字母保留给 shell 和环境变量;使用小写可以降低名称冲突的概率(参见 POSIX 规范,第四段)。

此外,这里不需要使用 eval


这可能会解决问题。不过,我很好奇 OP 是如何从黑名单文件中读取那些文件名的。 :) - sjsam
2
@sjsam 是的,很可能是一个 X/Y 问题 ;) - Benjamin W.
1
你可能想提到可以扩展为Bash数组变量(例如a=($line))或使用for进行迭代(可移植),但要避免问题中显示的eval和子shell方法,这会丢失各个文件名的身份。此外,对于使用--避免出现看起来像命令选项的名称也值得一些指导。 - Toby Speight
您可能希望通过设置IFS=来禁用单词拆分。 - chepner
@chepner 我同意这些都是有效的观点。我的回答解决了问题中显示的特定问题,因为问题没有显示如何读取模式。虽然我支持在答案中展示最佳实践,但我认为如果问题甚至没有提到可能出错的事情,那么不是每个答案都可以成为万能药并指出这些事情。 - Benjamin W.
@TobySpeight,前面的评论也适用于你的评论。 - Benjamin W.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接