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

Iterate over specific files in a directory using Bash find

Shellcheck doesn't like 我的 forfind 循环 Bash.

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

第 6 行: < < (find). 中的空 space 是做什么的 < 是否像往常一样重定向?如果是,重定向到 do 块意味着什么?

谁能帮忙解析一下?这是遍历目录中某种文件的正确方法吗?

In line one: What is '' file?

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

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

In line six: What does the empty space do in < < (find).

那里有两个独立的运算符。有 <,标准 I/O 重定向运算符,后跟 <(...) 构造,它是执行进程替换的 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 循环。

Are the < redirects, as usual? If they are, what does it mean to redirect into do block?

重定向到一个循环意味着该循环内的任何命令 reads from stdin 将从重定向的输入源读取。作为一个 副作用,循环内的所有内容 运行s 都在子 shell 中,它具有 对变量范围的影响:在 循环在循环外是不可见的。

Can someone help parse this out? Is this the right way to iterate over files of a certain kind in a directory?

郑重声明,我通常会通过管道 findxargs 来做到这一点, 尽管哪种解决方案最好在一定程度上取决于什么 你正在尝试做。你问题中的两个例子完全 不同的东西,目前还不清楚你到底想做什么 完成。

但是例如:

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

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

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

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

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 选项,则 NUL 字符是 find 在每个文件名末尾输出的内容。 (与 -exec 不同,-print0 不是 Posix 标准,因此不能保证它适用于每个 find 实现,但实际上它是普遍可用的。)

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