一个目录中的所有文件数组,除了一个。

3

尝试弄清楚如何包含除名为manifest.txt的一个之外的所有.txt文件。

FILES=(path/to/*.txt) 
4个回答

5

您可以使用扩展的全局模式

shopt -s extglob
files=(path/to/!(manifest).txt)
< p> !(模式列表) 模式匹配“除给定模式之外的所有内容”。

请注意,这仅排除 manifest.txt 而没有其他内容;例如mmanifest.txt仍将进入数组。


作为一个附带说明:匹配不到任何内容的通配符会扩展为其本身(参见手册此问题)。可以使用nullglob(扩展为空字符串)和failglob(打印错误消息)shell选项来更改此行为。

在我进行的一个小测试中,它对我不起作用。我得到了一个包含!(manifest).txt的数组。我认为你需要除了extglob之外还要使用nullglob - Fred
@Fred 看起来你没有打开 extglob?请注意,它可以在交互式 shell 中打开,但在非交互式 shell 中关闭,以防你尝试在脚本中使用。我认为不需要 nullglob - Benjamin W.
@BenjaminW。我可以确认我已经在交互式 shell 中重现了这个问题。只需要禁用 nullglob(其他没有更改),我就从预期的结果转变为我的评论中描述的结果。 - Fred
@Fred,如果你没有任何 .txt 文件的情况下呢?那是我能理解你所描述的唯一方式。 - Benjamin W.
@BenjaminW。是的,没有.txt文件;也许这种情况应该明确处理? - Fred
@Fred 我会添加一条注释,但这并不是针对此解决方案的特定说明。任何基于glob的解决方案都必须考虑到它,并且我不认为我想在所有答案中添加所有可能的注意事项列表。 - Benjamin W.

2
您可以逐个文件构建数组,避免不需要的文件:
declare -a files=()
for file in /path/to/files/*
do
  ! [[ -e "$file" ]] || [[ "$file" = */manifest.txt ]] || files+=("$file")
done

请注意,在for语句中使用globbing不会导致文件名中的空格(甚至是换行符)出现问题。 编辑 我添加了一个测试,用于处理globbing失败且未设置nullglob选项的情况下文件存在的情况。

1
我认为即使只有一个元素,最好使用关联数组来处理。请考虑以下内容:
$ touch f{1..6}.txt manifest.txt
$ ls *.txt
f1.txt      f3.txt      f5.txt      manifest.txt
f2.txt      f4.txt      f6.txt

你可以创建一个关联数组来排除你想要排除的名称:
declare -A exclude 
for f in f1.txt f5.txt manifest.txt; do 
    exclude[$f]=1
done

然后将不在关联数组中的文件添加到一个数组中:

files=()
for fn in *.txt; do
    [[ ${exclude[$fn]} ]] && continue
    files+=("$fn")  
done

$ echo "${files[@]}"
f2.txt f3.txt f4.txt f6.txt

这种方法允许从文件列表中排除任意数量的文件。

0
FILES=($(ls /path/to/*.txt | grep -wv '^manifest.txt$'))

1
如果文件名中包含空格和/或通配符(这是完全合法的),则此方法仍无法正常工作。尝试使用touch 'this * is * a * file.txt' manifest.txt命令创建文件,然后使用此方法并查看FILE数组包含的内容。 - Gordon Davisson
1
在一个空目录中运行我的 touch 命令,然后运行您的命令(在 $PWD/*.txt 上),然后运行 printf "'%s' " "${FILES[@]}",会给我返回 '/Users/gordon/tmp/manifest.txt' '/Users/gordon/tmp/this' 'manifest.txt' 'this * is * a * file.txt' 'is' 'manifest.txt' 'this * is * a * file.txt' 'a' 'manifest.txt' 'this * is * a * file.txt' 'file.txt' - Gordon Davisson
1
这仍然会扩展通配符。 为了防止这种情况,您需要对“$()”进行引用,但是这样最终会得到一个只有一个元素的数组。 - Benjamin W.
在我看来,运行良好。我没有看到任何反例。 - Grzegorz Górkiewicz
1
@GrzegorzGórkiewicz 你测试了我的例子吗?最新更新仍然失败(虽然稍微好了一些)。此外,请阅读BashFAQ关于为什么不应解析ls(1)输出的原因 - Gordon Davisson
显示剩余2条评论

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