【问题标题】:Array of all files in a directory, except one一个目录中所有文件的数组,除了一个
【发布时间】:2017-02-04 22:30:44
【问题描述】:

试图弄清楚如何包含所有.txt 文件,但名为manifest.txt 的文件除外。

FILES=(path/to/*.txt) 

【问题讨论】:

    标签: arrays bash


    【解决方案1】:

    您可以为此使用extended glob patterns

    shopt -s extglob
    files=(path/to/!(manifest).txt)
    

    !(<em>pattern-list</em>) 模式匹配“除给定模式之一之外的任何内容”。

    请注意,这完全不包括manifest.txt,仅此而已;例如,mmanifest.txt 仍然会进入数组。


    附带说明:一个完全不匹配的 glob 会扩展为自身(参见 the manualthis question)。可以使用nullglob(扩展为空字符串)和failglob(打印错误消息)shell 选项更改此行为。

    【讨论】:

    • 在我做的一个小测试中它对我不起作用。我得到一个包含!(manifest).txt 的数组我认为除了extglob 之外,您还需要nullglob
    • @Fred 看起来您没有打开extglob?请注意,它可以在交互式 shell 中打开,但在非交互式 shell 中关闭,以防您在脚本中尝试此操作。 nullglob 不需要,我会说。
    • @BenjaminW。我可以确认我已经在交互式外壳中复制了它。只需禁用nullglob(没有其他任何更改),我就可以从预期结果变为我评论中描述的结果。
    • @Fred 对于您根本没有任何 .txt 文件的情况?只有这样我才能得到你所描述的内容。
    • @BenjaminW。是的,没有.txt 文件;也许这种情况应该明确处理?
    【解决方案2】:

    你可以一次构建一个数组,避免你不想要的文件:

    declare -a files=()
    for file in /path/to/files/*
    do
      ! [[ -e "$file" ]] || [[ "$file" = */manifest.txt ]] || files+=("$file")
    done
    

    请注意,for 语句中的通配符不会导致文件名中的空格(甚至换行符)出现问题。

    编辑

    我添加了一个文件存在测试来处理 glob 失败且未设置 nullglob 选项的情况。

    【讨论】:

      【解决方案3】:

      我认为最好使用关联数组来处理,即使只有一个元素。

      考虑:

      $ 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
      

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

      【讨论】:

        【解决方案4】:
        FILES=($(ls /path/to/*.txt | grep -wv '^manifest.txt$'))
        

        【讨论】:

        • 如果文件名中有空格和/或通配符(这是完全合法的),这仍然不起作用。尝试touch 'this * is * a * file.txt' manifest.txt,然后使用它,然后查看FILE 数组包含的内容。
        • @GordonDavisson,即使我使用您的 touch 命令创建此文件,它也可以工作。请更正您的示例或解释。
        • @GrzegorzGórkiewicz 在一个空目录中运行我的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'
        • 这仍然会扩展通配符。你必须引用$() 来防止这种情况,但你最终会得到一个只有一个元素的数组。
        • @GrzegorzGórkiewicz 你测试我的例子了吗?最新的更新仍然失败(虽然不那么严重)。另外,请阅读 why you shouldn't parse the output of ls(1) 上的 BashFAQ 项目。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-02
        • 1970-01-01
        • 2011-08-05
        • 1970-01-01
        • 2019-11-21
        相关资源
        最近更新 更多