使用 Bash find 遍历目录中的特定文件

Posted

技术标签:

【中文标题】使用 Bash find 遍历目录中的特定文件【英文标题】:Iterate over specific files in a directory using 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 块是什么意思?

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

【问题讨论】:

【参考方案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

回答您的具体问题:

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

    &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具有 关于变量范围的含义:变量设置在 循环在循环外不可见。

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

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

但是例如:

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

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

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

【讨论】:

在第一个示例中计算所有降价文件中的单词。第二个例子来自建议。谢谢你的回答!

以上是关于使用 Bash find 遍历目录中的特定文件的主要内容,如果未能解决你的问题,请参考以下文章

在linux shell(bash)编程中,如何通过递归方式遍历文件

如何在bash中使用多个ifs遍历多个目录?

如何遍历bash中的子目录? [复制]

Linux Bash-文件查找

Bash:逐行遍历文件,找到特定的字符串并附加到每个后续行,直到找到相同的字符串

Android如何遍历特定目录下所有文件