【问题标题】:Bash: loop through files that DO NOT match extensionBash:遍历不匹配扩展名的文件
【发布时间】:2016-09-12 12:34:00
【问题描述】:

我正在编写一个 bash 脚本,该脚本需要在与特定扩展名不匹配的目录中循环文件。到目前为止,我发现以下代码会循环所有与给定扩展名匹配的文件:

for f in *.txt ; do
    echo $f;
done

insthead 如何遍历与指定扩展名不匹配的文件?

【问题讨论】:

  • 你可以使用^(.*[^\.txt])$

标签: regex bash file loops


【解决方案1】:

您可以使用 == 运算符进行模式匹配。

for f in *; do
    [[ $f == *.txt ]] && continue
    # [[ $f != *.txt ]] || continue
    ...
done

如果这可能在空目录中运行,请在循环之前使用shopt -s nullglob,或者将[ -e "$f" ] || continue 放在循环中。 (前者更可取,因为它避免不断检查文件是否存在。)

【讨论】:

  • 然后就是[ -e "$f" ] || continue
  • [ -e "$f" ] 将始终成功,因为 $f 是通过路径名扩展设置的。
  • @chepner ...除非没有文件可以匹配*
  • 好吧,当然,如果你担心一个空目录:)
  • @chepner:迟早会发生的。
【解决方案2】:

循环目录中不匹配特定扩展名的文件

你可以使用extglob:

shopt -s extglob

for f in *.!(txt); do
    echo "$f"
done

pattern *.!(txt) 将匹配所有带有点且点后没有 txt 的条目。


编辑:请参阅下面的 cmets。这是一个find 版本,用于循环当前目录中与特定扩展名不匹配的文件:

while IFS= read -d '' -r f; do
    echo "$f"
done < <(find . -maxdepth 1 -type f -not -name '*.txt' -print0)

【讨论】:

  • mkdir -p foo; touch foo/file.1.txt; shopt -s extglob; echo foo/*.!(txt)
  • 是的,我明白这一点。甚至可以使用 DOT 创建目录,该命令也可以找到该目录。我认为最好使用find -type f。 (见更新)
  • @anubhava 是的,这个工作正常。我还测试了 chepner 提出的解决方案,发现该解决方案更加灵活。
  • 好的,只要确保在 for 循环中也跳过子目录
【解决方案3】:

这样就可以了:

shopt -s extglob
for f in !(*.txt) ; do
    echo $f
done

您只需使用 !(glob_pat) 反转 glob 模式,要使用它,您需要启用扩展 glob。

如果你想忽略目录,那么:

shopt -s extglob
for f in !(*.txt) ; do
    [ -d "$f" ] && continue   # This will ignore dirs
    # [ -f "$f" ] && continue # This will ignore files
    echo $f
done

如果你想进入所有子目录,那么:

shopt -s extglob globstar
for f in !(*.txt) **/!(*.txt) ; do
    [ -d "$f" ] && continue   # This will ignore dirs
    # [ -f "$f" ] && continue # This will ignore files
    echo $f
done

【讨论】:

    【解决方案4】:

    find /path/to/look -type f -not -name "*.txt" -print0 | while read -r -d '' file_name
    do
    echo "$file_name"
    done
    

    当您的文件名可能不标准时。

    注意:

    如果您不希望递归搜索子文件夹中的文件,请在 -type f 之前添加 -maxdepth 1

    【讨论】:

      【解决方案5】:

      如果您可以接受GNU 解决方案,请尝试一下:

      for f in $(find . -maxdepth 1 -type f \! -name \*.txt) ; do
        printf "%s\n" "${f}"
      done
      

      如果文件名中包含特殊字符,例如(空格),这将会中断。

      为了安全,还是GNU,试试吧:

      find . -maxdepth 1 -type f \! -name \*.txt -printf "%p\0" | xargs -0 sh -c '
          for f ; do
            printf "%s\n" "${f}"
          done' arg0
      

      【讨论】:

        【解决方案6】:
        for f in $(ls --hide="*.txt")
        do
            echo $f
        done
        

        【讨论】:

          猜你喜欢
          • 2020-09-27
          • 1970-01-01
          • 1970-01-01
          • 2019-01-19
          • 2018-10-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多