【问题标题】:Iterate over specific files in a directory using Bash find使用 Bash find 遍历目录中的特定文件
【发布时间】:2015-09-06 03:19:46
【问题描述】:

Shellcheck doesn't like 我的 for 在 Bash 中循环 find。

for f in $(find $src -maxdepth 1 -name '*.md'); do wc -w < "$f" >> $path/tmp.txt; done

它建议:

1  while IFS= read -r -d '' file
2  do
3      let count++
4      echo "Playing file no. $count"
5      play "$file"
6  done <   <(find mydir -mtime -7 -name '*.mp3' -print0)
7  echo "Played $count files"

大部分我都明白了,但有些东西还不清楚。

第一行:什么是'' file?

第六行:&lt; &lt; (find). 中的空白空间有什么作用?&lt; 是否像往常一样重定向?如果是,重定向到do 块是什么意思?

有人可以帮忙分析一下吗?这是在目录中迭代某种文件的正确方法吗?

【问题讨论】:

    标签: bash command-line terminal shellcheck


    【解决方案1】:

    通常,如果您想通过目录树进行递归搜索,则需要使用find(尽管使用现代 bash,您可以设置 shell 选项 globstar,正如 shellcheck 建议的那样)。但在这种情况下,您指定了 -maxdepth 1,因此您的 find 命令只是列出与模式 "$src"/*.md 匹配的文件。既然如此,使用glob(模式)就简单多了:

    for f in "$src"/*.md; do
      wc -w < "$f"
    done >> "$path"/tmp.txt
    

    (为了安全起见,我还引用了所有变量扩展,并移动了输出重定向,使其适用于整个 for 循环,这样效率更高。)

    如果您需要使用find(因为glob 不起作用),那么您应该尝试使用-exec 选项来查找,这不需要摆弄其他选项来避免错误处理的特殊字符在文件名中。例如,您可以这样做:

    find "$src" -maxdepth 1 -name '*.md' -exec do wc -w {} + >> "$path"/tmp.txt
    

    回答您的具体问题:

    1. 在IFS= read -r -d '' file 中,'' 是-d 选项的参数。该选项用于指定分隔要读取的行的字符;默认情况下,使用换行符,以便read 一次读取一行。空字符串与指定 NUL 字符相同,如果您指定 -print0 选项,这就是 find 在每个文件名末尾输出的内容。 (与 -exec 不同,-print0 不是 Posix 标准,因此不能保证它适用于每个 find 实现,但实际上它非常普遍。)

    2. &lt; 和&lt;(...) 之间的空格是为了避免创建令牌&lt;&lt;,这将指示此处的文档。相反,它指定来自进程替换 (&lt;(...)) 的重定向 (&lt;)。

    【讨论】:

      【解决方案2】:

      第一行:什么是''文件?

      根据help read,'' 是-d 参数的参数:

      -d delim    continue until the first character of 
                  DELIM is read, rather than newline
      

      第六行:

      那里有两个独立的运算符。有&lt;,标准I/O 重定向操作符,后面是&lt;(...) 构造,这是一个特定于bash 的构造,执行进程替换:

      Process Substitution
      
          Process  substitution  is  supported on systems that
          support named pipes (FIFOs) or the /dev/fd method of naming
          open files.  It takes the form of <(list) or >(list).  The
          process list is run with its  input  or output  connected
          to  a FIFO or some file in /dev/fd...
      

      所以这是将find 命令的输出发送到do 循环。

      重定向到一个循环意味着该循环内的任何命令 从stdin 读取的数据将从重定向的输入源读取。作为一个 副作用,该循环内的所有内容都在一个子shell中运行,该子shell具有 关于变量范围的含义:变量设置在 循环在循环外不可见。

      有人可以帮忙分析一下吗?这是在目录中迭代某种文件的正确方法吗?

      为了记录,我通常会通过管道 find 到 xargs 来做到这一点, 尽管哪种解决方案最好在一定程度上取决于什么 你正在尝试做。您问题中的两个示例完全可以 不同的东西,不清楚你到底想做什么 完成。

      但是例如:

      find $src -maxdepth 1 -name '*.md' -print0 |
        xargs -0 -iDOC wc -w DOC
      

      这将在所有*.md 文件上运行wc。 -print0 到 find (以及-0 到xargs)允许此命令正确处理 带有嵌入空格的文件名(例如,This is my file.md)。如果 你知道你没有这些,你只需要:

      find $src -maxdepth 1 -name '*.md' |
        xargs -iDOC wc -w DOC
      

      【讨论】:

      • 在第一个示例中计算所有降价文件中的单词。第二个例子来自建议。谢谢你的回答!
      猜你喜欢
      • 2013-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-25
      • 2021-01-16
      • 2014-10-02
      • 1970-01-01
      • 2019-01-16
      相关资源
      最近更新 更多