arrays - variable - shell split字符串




捕获find的输出。-print0到一个bash数组中 (9)

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

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

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

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

find . | wc -l

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

我怎样才能做到这一点?

这不起作用:

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

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


Bash从来没有擅长处理文件名(或任何文本),因为它使用空格作为列表分隔符。

我建议与sh库一起使用python。


Gordon Davisson的答案对于bash来说很棒。 然而,zsh用户有一个有用的捷径:

首先,将你的字符串放在一个变量中:

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

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

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

有一个技巧: ^@是NUL字符。 要做到这一点,你必须先按Ctrl + V再按Ctrl + @。

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

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

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

B=( /tmp/** )

也许你正在寻找xargs:

find . -print0 | xargs -r0 do_something_useful

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


你可以安全地做这个计数:

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

(它为每个找到的文件/目录打印换行符,然后计算打印出的换行符......)


我是新人,但我相信这是一个答案。 希望它能帮助某人:

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

我认为更优雅的解决方案存在,但我会抛弃这个。这也适用于包含空格和/或换行符的文件名:

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

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

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

这个页面提供了一个很好的例子,更多的请看高级Bash脚本指南中的第26章


老问题,但没有人提出这个简单的方法,所以我想我会的。 当然,如果你的文件名有ETX,这并不能解决你的问题,但我怀疑它适用于任何真实世界的场景。 尝试使用null似乎违反了默认的IFS处理规则。 依据查找选项和错误处理季节到您的口味。

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

自Bash 4.4以来,内建mapfile具有-d开关(用于指定分隔符,类似于read语句的-d开关),分隔符可以是空字节。 因此,标题中的问题是一个很好的答案

捕获find . -print0输出find . -print0 find . -print0到一个bash数组中

是:

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

这与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[@]}






delimiter