捕获发现的输出。 -print0成一个bash阵列 捕获发现的输出。 -print0成一个ba

2019-06-05 05:57发布

使用find . -print0 find . -print0似乎是获得在bash的文件列表的唯一可靠的方式因含有空格,换行,引号等文件名的可能性

不过,我有一个很难实际进行查找的输出中bash或与其他命令行实用程序非常有用。 我已成功地利用输出的唯一方法是通过管道它Perl和改变Perl的IFS为null:

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

这个例子打印找到的文件的数量,避免换行的文件名中破坏计数危险,因为会出现带:

find . | wc -l

由于大多数的命令行程序不支持空分隔的投入,我想最好的办法是捕捉到的输出find . -print0 find . -print0在bash阵列,就像我在perl的做了上面的代码,然后与任务,不管它可能会继续。

我怎样才能做到这一点?

这不起作用:

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

一个更普遍的问题可能是: 我该怎么做有用的事情,在bash的文件列表?

Answer 1:

从无耻地窃取Greg的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内建命令(例如while ),管道版本执行它们在子shell,并且它们设置任何变量(例如数组a )丢失时退出。 cmd1 < <(cmd2)只运行CMD2在子shell,以使阵列住过去施工。 警告:这种形式的重定向只在bash可用,甚至没有庆典在SH-仿真模式; 你必须以你的脚本#!/bin/bash

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

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通过文件列表,而不是标准输入。



Answer 2:

也许你正在寻找xargs的:

find . -print0 | xargs -r0 do_something_useful

选项-L 1可能是你太有用,这使得xargs的高管do_something_useful只有1个文件的说法。



Answer 3:

主要的问题是,分隔符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或类似的还可以做的工作什么的。



Answer 4:

计算文件的另一种方式:

find /DIR -type f -print0 | tr -dc '\0' | wc -c 


Answer 5:

由于击4.4,内建mapfile具有-d开关(以指定的分隔符,类似于-d所述的开关read语句),并且分隔符可以是一个空字节。 因此,一个很好的答案,在标题的问题

捕获的输出find . -print0 find . -print0成一个bash阵列

是:

mapfile -d '' ary < <(find . -print0)


Answer 6:

您可以放心地做这个计数:

find . -exec echo ';' | wc -l

(它输出找到的每个文件/目录一个换行符,再算上打印出来的换行符...)



Answer 7:

我觉得更优雅的解决方案存在,但我折腾这一个在这还将为用空格和/或换行符的文件名工作:

i=0;
for f in *; do
  array[$i]="$f"
  ((i++))
done

然后,您可以如列出文件一个接一个(在这种情况下,以相反的顺序):

for ((i = $i - 1; i >= 0; i--)); do
  ls -al "${array[$i]}"
done

该页面提供了一个很好的例子,并为更见第26章中的高级Bash脚本编程指南 。



Answer 8:

如果你能避免xargs的:

man ruby | less -p 777 
IFS=$'\777' 
#array=( $(find ~ -maxdepth 1 -type f -exec printf "%s\777" '{}' \; 2>/dev/null) ) 
array=( $(find ~ -maxdepth 1 -type f -exec printf "%s\777" '{}' + 2>/dev/null) ) 
echo ${#array[@]} 
printf "%s\n" "${array[@]}" | nl 
echo "${array[0]}" 
IFS=$' \t\n' 


Answer 9:

我是新的,但我相信这个答案是什么; 希望它可以帮助别人:

STYLE="$HOME/.fluxbox/styles/"

declare -a array1

LISTING=`find $HOME/.fluxbox/styles/ -print0 -maxdepth 1 -type f`


echo $LISTING
array1=( `echo $LISTING`)
TAR_SOURCE=`echo ${array1[@]}`

#tar czvf ~/FluxieStyles.tgz $TAR_SOURCE


Answer 10:

这类似于Stephan202的版本,但这些文件(和目录)的一次全部放入数组。 在for这里环路仅仅是“做有用的事情”:

files=(*)                        # put files in current directory into an array
i=0
for file in "${files[@]}"
do
    echo "File ${i}: ${file}"    # do something useful 
    let i++
done

为了得到一个数:

echo ${#files[@]}


Answer 11:

老问题,但没有人提出这种简单的方法,所以我想我会的。 诚然,如果你的文件名有ETX,这并不能解决你的问题,但我怀疑它服务于任何真实世界的场景。 尝试使用空,似乎默认IFS处理规则相抵触运行。 季节你的口味与查找选项和错误处理。

savedFS="$IFS"
IFS=$'\x3'
filenames=(`find wherever -printf %p$'\x3'`)
IFS="$savedFS"


Answer 12:

戈登·戴维森的答案是伟大的庆典。 然而有用的快捷方式为用户zsh的存在:

首先,将您字符串变量:

A="$(find /tmp -type f -print0)"

接着,分割这个变量并将其存储在数组中:

B=( ${(s/^@/)A} )

还有一招: ^@就是空字符。 要做到这一点,你必须键入Ctrl + V键,然后按Ctrl + @。

您可以检查$ B的每一个条目包含正确的价值:

for i in "$B[@]"; echo \"$i\"

细心的读者可能会注意到调用find命令可以使用可避免在大多数情况下**语法。 例如:

B=( /tmp/** )


Answer 13:

巴什从未善于处理文件名(或任何文本真的),因为它使用空格作为列表分隔符。

我建议你使用python与SH库,而不是。



文章来源: Capturing output of find . -print0 into a bash array