使用find。 -print0似乎是获取bash文件列表的唯一安全方式,因为文件名包含空格,换行符,引号等的可能性。
但是,我有一个很难的时间实际上使得find的输出在bash或其他命令行实用程序有用。我已经设法利用输出的唯一方法是将其管道到perl,并将perl的IFS更改为null:
find . -print0 | perl -e '$/="\0"; @files=<>; print $#files;'
此示例打印找到的文件数,避免换行符在文件名中损坏计数的危险,如下所示:
find . | wc -l
由于大多数命令行程序不支持空定界输入,我想最好的事情是捕获find的输出。 -print0在一个bash数组,就像我在上面的perl代码片段,然后继续任务,无论它可能是什么。
我如何做到这一点?
这不工作:
find . -print0 | ( IFS=$'\0' ; array=( $( cat ) ) ; echo ${#array[@]} )
一个更常见的问题可能是:我如何可以使用bash中的文件列表做有用的事情?
无耻地从
Greg’s BashFAQ被盗:
unset a i while IFS= read -r -d $'\0' file; do a[i++]="$file" # or however you want to process each file done < <(find /tmp -type f -print0)
注意,这里使用的重定向构造(cmd1<(cmd2))类似于但更不常见的管道(cmd2 | cmd1) - 如果命令是shell内置命令管道版本在子shell中执行它们,并且它们设置的任何变量(例如,数组a)在它们退出时丢失。 cmd1< <(cmd2)仅在子shell中运行cmd2,因此该数组过期。警告:此重定向形式仅在bash中可用,在sh-emulation模式下甚至不可用;您必须使用#!/ bin / bash启动脚本。 此外,因为文件处理步骤(在这种情况下,只是一个[i] =“$文件”,但你可能想直接在循环中做某些fancier)的输入重定向,它不能使用任何可能读取的命令stdin。为了避免这种限制,我倾向于使用:
unset a i while IFS= read -r -u3 -d $'\0' file; do a[i++]="$file" # or however you want to process each file done 3< <(find /tmp -type f -print0)
…通过单元3传递文件列表,而不是stdin。