如何遍历find返回的文件名? [英] How to loop through file names returned by find?

查看:27
本文介绍了如何遍历find返回的文件名?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

x=$(find .-name "*.txt")回声$x

如果我在 Bash shell 中运行上面的代码,我得到的是一个包含多个文件名的字符串,由空格分隔,而不是一个列表.

当然,我可以进一步用空格将它们分开以获得列表,但我相信有更好的方法来做到这一点.

那么循环遍历 find 命令的结果的最佳方法是什么?

解决方案

TL;DR:如果你只是为了最正确的答案,你可能想要我的个人偏好(见本文底部):

>

#对每个文件执行一次`process`找 .-name '*.txt' -exec 进程 {} ;

如果您有时间,请通读其余部分以了解几种不同的方法以及其中大多数方法的问题.


完整答案:

最好的方法取决于您想做什么,但这里有几个选项.只要子树中的文件或文件夹的名称中没有空格,您就可以遍历文件:

for i in $x;do # 不推荐,会在空格处中断处理$i"完毕

稍微好一点,去掉临时变量x:

for i in $(find -name *.txt);do # 不推荐,会在空格处中断处理$i"完毕

在可能的情况下使用 glob 要好得多.空白安全,用于当前目录中的文件:

for i in *.txt;do # 空格安全但不是递归的.处理$i"完毕

通过启用 globstar 选项,您可以对这个目录和所有子目录中的所有匹配文件进行 glob:

# 确保 globstar 已启用shopt -s globstar对于 **/*.txt 中的 i;do # 空格安全和递归处理$i"完毕

在某些情况下,例如如果文件名已经在一个文件中,你可能需要使用 read:

# IFS= 确保它不会修剪前导和尾随空格# -r 防止解释  转义.而 IFS= 读取 -r 行;do # 空格安全的 EXCEPT 换行符处理$line"完成<文档名称

通过适当设置分隔符,

read 可以安全地与 find 结合使用:

查找.-name '*.txt' -print0 |而 IFS= read -r -d '' 行;做处理$line"完毕

对于更复杂的搜索,您可能希望使用 find,或者使用它的 -exec 选项或使用 -print0 |xargs -0:

#对每个文件执行一次`process`找 .-name *.txt -exec process {} ;# 将所有文件作为参数执行一次 `process`*:找 .-name *.txt -exec 进程 {} +# 使用 xargs*找 .-name *.txt -print0 |xargs -0 进程# 在每个文件名后使用带参数的 xargs(意味着每个文件名运行一次)找 .-name *.txt -print0 |xargs -0 -I{} 处理 {} 参数

find 也可以使用 -execdir 而不是 -exec 在运行命令之前 cd 到每个文件的目录,并且可以进行交互(在为每个文件运行命令之前提示)使用 -ok 而不是 -exec(或 -okdir 而不是 -execdir).

*:从技术上讲,findxargs(默认情况下)都将使用命令行中可以容纳的尽可能多的参数运行命令,次数为它需要通过所有文件.在实践中,除非您有大量文件,否则这无关紧要,并且如果您超出了长度但需要在同一命令行上全部使用,您是 SOL 会找到不同的方法.

x=$(find . -name "*.txt")
echo $x

if I run the above piece of code in Bash shell, what I get is a string containing several file names separated by blank, not a list.

Of course, I can further separate them by blank to get a list, but I'm sure there is a better way to do it.

So what is the best way to loop through the results of a find command?

解决方案

TL;DR: If you're just here for the most correct answer, you probably want my personal preference (see the bottom of this post):

# execute `process` once for each file
find . -name '*.txt' -exec process {} ;

If you have time, read through the rest to see several different ways and the problems with most of them.


The full answer:

The best way depends on what you want to do, but here are a few options. As long as no file or folder in the subtree has whitespace in its name, you can just loop over the files:

for i in $x; do # Not recommended, will break on whitespace
    process "$i"
done

Marginally better, cut out the temporary variable x:

for i in $(find -name *.txt); do # Not recommended, will break on whitespace
    process "$i"
done

It is much better to glob when you can. White-space safe, for files in the current directory:

for i in *.txt; do # Whitespace-safe but not recursive.
    process "$i"
done

By enabling the globstar option, you can glob all matching files in this directory and all subdirectories:

# Make sure globstar is enabled
shopt -s globstar
for i in **/*.txt; do # Whitespace-safe and recursive
    process "$i"
done

In some cases, e.g. if the file names are already in a file, you may need to use read:

# IFS= makes sure it doesn't trim leading and trailing whitespace
# -r prevents interpretation of  escapes.
while IFS= read -r line; do # Whitespace-safe EXCEPT newlines
    process "$line"
done < filename

read can be used safely in combination with find by setting the delimiter appropriately:

find . -name '*.txt' -print0 | 
    while IFS= read -r -d '' line; do 
        process "$line"
    done

For more complex searches, you will probably want to use find, either with its -exec option or with -print0 | xargs -0:

# execute `process` once for each file
find . -name *.txt -exec process {} ;

# execute `process` once with all the files as arguments*:
find . -name *.txt -exec process {} +

# using xargs*
find . -name *.txt -print0 | xargs -0 process

# using xargs with arguments after each filename (implies one run per filename)
find . -name *.txt -print0 | xargs -0 -I{} process {} argument

find can also cd into each file's directory before running a command by using -execdir instead of -exec, and can be made interactive (prompt before running the command for each file) using -ok instead of -exec (or -okdir instead of -execdir).

*: Technically, both find and xargs (by default) will run the command with as many arguments as they can fit on the command line, as many times as it takes to get through all the files. In practice, unless you have a very large number of files it won't matter, and if you exceed the length but need them all on the same command line, you're SOL find a different way.

这篇关于如何遍历find返回的文件名?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆