捕获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
)在subshell中执行它们,并且它们设置的任何变量(例如数组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