如何捕获ls或find命令的输出以将所有文件名存储在数组中?

37
需要逐个处理当前目录中的文件。我正在寻找一种方法,将 lsfind 命令的输出结果作为数组元素存储起来,这样我就可以根据需要操作数组元素。

@ SiegeX 我该怎么接受答案?我已经回复和感谢那些给出最好回答并在获得权限后投票赞成的人了。我还能做什么? - fzkl
4个回答

54
回答你的确切问题,使用以下内容:
arr=( $(find /path/to/toplevel/dir -type f) )

示例

$ find . -type f
./test1.txt
./test2.txt
./test3.txt
$ arr=( $(find . -type f) )
$ echo ${#arr[@]}
3
$ echo ${arr[@]}
./test1.txt ./test2.txt ./test3.txt
$ echo ${arr[0]}
./test1.txt

然而,如果你只想逐个处理文件,你可以使用 find-exec 选项(如果脚本比较简单),或者像下面这样循环遍历 find 返回的结果:

while IFS= read -r -d $'\0' file; do
  # stuff with "$file" here
done < <(find /path/to/toplevel/dir -type f -print0)

2
@ChandanChoudhury read -r -d $'\0' 告诉 read 命令不将反斜杆视为特殊转义字符,并使用 NUL 字符作为定界符来分隔每个单词,因为我们告诉 find 使用 -print0 作为定界符。 IFS= 部分实质上取消了特殊的内部字段分隔符环境变量,因此它不会对制表符、空格或新行执行单词拆分操作。简而言之,这些命令使您可以遍历任何文件名,无论它包含什么类型的字符。 - SiegeX
IFS= 移到 while 前面,这样行得通吗:IFS = ; while ... - user2066805
此外,使用这种控制结构和使用管道 find ... | while .... 之间有什么区别吗? - user2066805

10
for i in `ls`; do echo $i; done;

再简单不过了!

编辑:根据Dennis Williamson的评论,似乎您可以!

编辑2:尽管OP特别询问如何解析ls的输出,但我只想指出,正如下面的评论者所说,正确的答案是“不要这样做”。改用for i in *或类似方法。


3
for i in * 这个命令甚至更简单! - Dennis Williamson
6
不要解析ls!使用for i in *; do ...执行相同的操作,但它不会被文件名中的奇怪字符所困扰,并且运行得更快(因为它不会生成另一个进程)。 - Gordon Davisson
2
@DennisWilliamson 有没有办法使用一个变量(包含路径)来代替 *for in in $path/* - PHP Learner
@PHPLearner:是的,就像你发布的那样,但你应该引用变量。for f in "$path"/* - Dennis Williamson
@GordonDavisson for i in *; do echo "$i" done 在一个空目录中会输出 * - Alois Mahdal
@AloisMahdal 是的;如果没有匹配的文件(使用 *,这意味着“如果没有文件”),shell glob扩展会保留glob。在许多情况下,这会导致“找不到文件”的类型错误,如果这是您想要的结果,则无妨。但如果这在您的脚本中是个问题,可以在其前面使用 shopt -s nullglob(并在后面使用 shopt -u nullglob 以避免以后出现问题),或者在循环中添加 if [[ ! -e "$i" ]]; then continue; fi,这样它就会跳过不存在的文件。 - Gordon Davisson

4

您实际上不需要使用ls/find来查找当前目录中的文件。

只需使用for循环:

for files in *; do 
    if [ -f "$files" ]; then
        # do something
    fi
done

如果您想处理隐藏文件,您可以设置相应的选项:

shopt -s dotglob

这个命令只适用于bash。


%files 应该改为 $files。另外,如果您使用的是 Bash 4.X 版本,可以设置 shopt -s globstar 并使用 for files in **; do 来进行递归操作,完全不需要使用 find 命令。 - SiegeX
谢谢!我已经纠正了错误;顺便说一下,我有Bash 4,但是OP(或其他读者)可能没有它 :) - marco

-1

根据您想要做什么,您可以使用xargs:

ls directory | xargs cp -v dir2

例如,xargs将对返回的每个项目进行操作。

@Fritschy:如果你的cp支持,你可以使用xargs cp -v --target-directory dir2 - Dennis Williamson
@Dennis:确实如此,但它仍然在上面缺失。 - Marcus Borkenhagen
@Fritschy:失败的一个原因可能是文件名中包含空格。使用 find ... -print0 | xargs -0 可以解决这个问题。它到底出了什么问题?对我来说它是有效的。 - Dennis Williamson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接