捕获find的输出。

使用find . -print0 find . -print0似乎是获得bash文件列表的唯一安全方式,因为文件名可能包含空格,换行符,引号等。

但是,我很难在bash或其他命令行工具中使find的输出有用。 我设法使用输出的唯一方法是将它输出到perl,并将perl的IFS更改为null:

find . -print0 | perl -e '$/=""; @files=<>; print $#files;'

这个例子打印找到的文件数量,避免文件名中换行符破坏计数的危险,就像下面这样:

find . | wc -l

由于大多数命令行程序不支持以空格分隔的输入,我认为最好的办法是捕获find . -print0的输出find . -print0 find . -print0放在bash数组中,就像我在上面的perl代码片段中完成的那样,然后继续执行任务,不管它是什么。

我怎样才能做到这一点?

这不起作用:

find . -print0 | ( IFS=$'' ; array=( $( cat ) ) ; echo ${#array[@]} )

一个更普遍的问题可能是: 我如何用bash中的文件列表来做有用的事情?


无耻地从Greg的BashFAQ窃取:

unset a i
while IFS= read -r -d $'' file; do
    a[i++]="$file"        # or however you want to process each file
done < <(find /tmp -type f -print0)

请注意,此处使用的重定向结构( cmd1 < <(cmd2) )与更常用的管道( cmd2 | cmd1 )类似,但不完全相同 - 如果命令是shell内建的(例如while )在subshel​​l中执行它们,并且它们设置的任何变量(例如数组a )在它们退出时都会丢失。 cmd1 < <(cmd2)只在子shell中运行cmd2,所以该数组超出其构造。 警告:这种形式的重定向只能在bash中使用,甚至在sh-emulation模式下不能使用bash; 你必须用#!/bin/bash启动你的脚本。

另外,由于文件处理步骤(在这种情况下,只是a[i++]="$file" ,但您可能想在循环中直接做一些更奇特的事情)将其输入重定向,它不能使用任何可能读取的命令标准输入。 为了避免这种限制,我倾向于使用:

unset a i
while IFS= read -r -u3 -d $'' file; do
    a[i++]="$file"        # or however you want to process each file
done 3< <(find /tmp -type f -print0)

...它通过单元3传递文件列表,而不是标准输入。


也许你正在寻找xargs:

find . -print0 | xargs -r0 do_something_useful

-L1选项对你也很有用,这使得xargs exec do_something_useful只有一个文件参数。


主要的问题是,分隔符NUL( 0)在这里没有用处,因为不可能为IFS分配一个NUL值。 所以作为优秀的程序员,我们注意,我们程序的输入是它能够处理的。

首先我们创建一个小程序,它为我们完成这一部分:

#!/bin/bash
printf "%s" "$@" | base64

...并将其称为base64str(不要忘记chmod + x)

其次,我们现在可以使用一个简单而直接的for循环:

for i in `find -type f -exec base64str '{}' ;`
do 
  file="`echo -n "$i" | base64 -d`"
  # do something with file
done

所以诀窍是,一个base64字符串没有任何迹象给bash带来麻烦 - 当然xxd或类似的东西也可以完成这项工作。

链接地址: http://www.djcxy.com/p/25565.html

上一篇: Capturing output of find .

下一篇: ${1:+"$@"} in /bin/sh