使用 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
?
第六行:< < (find).
中的空白空间有什么作用?<
是否像往常一样重定向?如果是,重定向到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
实现,但实际上它非常普遍。)
<
和<(...)
之间的空格是为了避免创建令牌<<
,这将指示此处的文档。相反,它指定来自进程替换 (<(...)
) 的重定向 (<
)。
【讨论】:
【参考方案2】:第一行:什么是''文件?
根据help read
,''
是-d
参数的参数:
-d delim continue until the first character of
DELIM is read, rather than newline
第六行:
那里有两个独立的运算符。有<
,标准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
循环。
重定向到一个循环意味着该循环内的任何命令
从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
【讨论】:
在第一个示例中计算所有降价文件中的单词。第二个例子来自建议。谢谢你的回答!以上是关于使用 Bash find 遍历目录中的特定文件的主要内容,如果未能解决你的问题,请参考以下文章
在linux shell(bash)编程中,如何通过递归方式遍历文件