1

Shellcheck 不喜欢我在 Bash 中的for过度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

在第 6 行:< < (find). Are the <redirects中的空白区域像往常一样做什么?do如果是,重定向到块是什么意思?

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

4

2 回答 2

1

In line one: What is '' file?

According to help read, that '' is an argument to the -d parameter:

-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).

There are two separate operators there. There is <, the standard I/O redirection operator, followed by a <(...) construct, which is a bash-specific construct that performs process substitution:

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...

So this is is sending the output of the find command into the do loop.

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

Redirect into a loop means that any command inside that loop that reads from stdin will read from the redirected input source. As a side effect, everything inside that loop runs in a subshell, which has implications with respect to variable scope: variables set inside the loop won't be visible outside the loop.

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

For the record, I would typically do this by piping find to xargs, although which solution is best depends to a certain extend on what you're trying to do. The two examples in your question do completely different things, and it's not clear what you're actually trying to accomplish.

But for example:

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

This would run wc on all the *.md files. The -print0 to find (and the -0 to xargs) permit this command to correctly handle filenames with embedded whitespace (e.g., This is my file.md). If you know you don't have any of those, you just do:

find $src -maxdepth 1 -name '*.md' |
  xargs -iDOC wc -w DOC
于 2015-06-20T04:01:10.520 回答
1

find通常,如果您想通过目录树进行递归搜索,则需要使用(尽管使用现代 bash,您可以设置 shell 选项globstar,如 shellcheck 建议的那样)。但是在这种情况下,您指定了 -maxdepth 1,因此您的find命令只是列出与 pattern 匹配的文件"$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 字符相同,find如果指定-print0选项,则在每个文件名末尾输出。(与-exec, 不同,-print0它不是 Posix 标准,因此不能保证它适用于每个find实现,但实际上它非常普遍。)

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

于 2015-06-20T04:10:11.623 回答