使用 Bash find 遍历目录中的特定文件
Iterate over specific files in a directory using Bash find
Shellcheck doesn't like 我的 for
在 find
循环 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?
郑重声明,我通常会通过管道 find
到 xargs
来做到这一点,
尽管哪种解决方案最好在一定程度上取决于什么
你正在尝试做。你问题中的两个例子完全
不同的东西,目前还不清楚你到底想做什么
完成。
但是例如:
find $src -maxdepth 1 -name '*.md' -print0 |
xargs -0 -iDOC wc -w DOC
这将 运行 wc
所有 *.md
文件。 -print0
到 find
(以及 -0
到 xargs
)允许此命令正确处理
带有嵌入空格的文件名(例如,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
回答您的具体问题:
在IFS= read -r -d '' file
中,''
是-d
选项的参数。该选项用于指定分隔要读取的行的字符;默认情况下,使用换行符以便 read
一次读取一行。空字符串与指定 NUL 字符相同,如果指定 -print0
选项,则 NUL 字符是 find
在每个文件名末尾输出的内容。 (与 -exec
不同,-print0
不是 Posix 标准,因此不能保证它适用于每个 find
实现,但实际上它是普遍可用的。)
<
和 <(...)
之间的 space 是为了避免创建令牌 <<
,这将指示此处文档。相反,它指定了来自进程替换 (<(...)
) 的重定向 (<
)。
Shellcheck doesn't like 我的 for
在 find
循环 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?
郑重声明,我通常会通过管道 find
到 xargs
来做到这一点,
尽管哪种解决方案最好在一定程度上取决于什么
你正在尝试做。你问题中的两个例子完全
不同的东西,目前还不清楚你到底想做什么
完成。
但是例如:
find $src -maxdepth 1 -name '*.md' -print0 |
xargs -0 -iDOC wc -w DOC
这将 运行 wc
所有 *.md
文件。 -print0
到 find
(以及 -0
到 xargs
)允许此命令正确处理
带有嵌入空格的文件名(例如,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
回答您的具体问题:
在
IFS= read -r -d '' file
中,''
是-d
选项的参数。该选项用于指定分隔要读取的行的字符;默认情况下,使用换行符以便read
一次读取一行。空字符串与指定 NUL 字符相同,如果指定-print0
选项,则 NUL 字符是find
在每个文件名末尾输出的内容。 (与-exec
不同,-print0
不是 Posix 标准,因此不能保证它适用于每个find
实现,但实际上它是普遍可用的。)<
和<(...)
之间的 space 是为了避免创建令牌<<
,这将指示此处文档。相反,它指定了来自进程替换 (<(...)
) 的重定向 (<
)。