使用Bash find迭代目录中的特定文件

时间:2015-06-20 03:43:57

标签: bash command-line terminal shellcheck

在Pash中

Shellcheck doesn't like 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

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

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

2 个答案:

答案 0 :(得分:1)

  

第一行:什么是&#39;&#39;文件?

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

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

第六行:空白空间做什么&lt; &LT; (找到)。

那里有两个独立的运营商。有<,标准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 循环。

  

是&lt;像往常一样重定向?如果是,那么重定向到do block意味着什么?

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

  

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

为了记录,我通常会通过管道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

答案 1 :(得分: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字符相同,如果指定find选项,则-print0在每个文件名末尾输出。 (与-exec不同,-print0不是Posix标准,因此无法保证与每个find实现一起使用,但实际上它通常可用。)

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