为了账号安全,请及时绑定邮箱和手机立即绑定

如何将“ find”命令结果存储为Bash中的数组

/ 猿问

如何将“ find”命令结果存储为Bash中的数组

我试图将结果保存find为数组。这是我的代码:


#!/bin/bash


echo "input : "

read input


echo "searching file with this pattern '${input}' under present directory"

array=`find . -name ${input}`


len=${#array[*]}

echo "found : ${len}"


i=0


while [ $i -lt $len ]

do

echo ${array[$i]}

let i++

done

我在当前目录下得到2个.txt文件。所以我期望'2'作为的结果${len}。但是,它打印1。原因是将所有结果都find作为一个元素。我怎样才能解决这个问题?


PS

我发现了几个解决方案,在计算器上有关类似问题。但是,它们有些不同,因此我无法申请。我需要在循环之前将结果存储在变量中。再次感谢。


查看完整描述

3 回答

?
若吾皇

这是将输出结果find放入bash数组的一种解决方案:


array=()

while IFS=  read -r -d $'\0'; do

    array+=("$REPLY")

done < <(find . -name "${input}" -print0)

这很棘手,因为通常文件名可以包含空格,换行符和其他对脚本不利的字符。使用find并使文件名安全地分开的唯一方法是使用,该命令-print0将打印以空字符分隔的文件名。如果bash的readarray/ mapfile函数支持以空分隔的字符串,但不支持,则不会带来太大的麻烦。Bash的做法read使我们进入了上面的循环。


这个怎么运作

第一行创建一个空数组: array=()


每次read执行该语句时,都会从标准输入中读取以空分隔的文件名。该-r选项告诉read您保留反斜杠字符。该-d $'\0'告诉read输入将以空分隔。由于我们省略了名称read,因此外壳程序将输入放入默认名称:中REPLY。


该array+=("$REPLY")语句将新文件名附加到数组array。


最后一行结合了重定向和命令替换,以将输出提供find给while循环的标准输入。


为什么要使用流程替代?

如果我们不使用流程替换,则循环可以写成:


array=()

find . -name "${input}" -print0 >tmpfile

while IFS=  read -r -d $'\0'; do

    array+=("$REPLY")

done <tmpfile

rm -f tmpfile

在上面,的输出find存储在一个临时文件中,该文件用作while循环的标准输入。进程替换的想法是使这些临时文件变得不必要。因此,与其让while循环从其获取标准输入tmpfile,不如让循环从其获取标准输入<(find . -name ${input} -print0)。


流程替换非常有用。在许多要从文件中读取命令的地方,可以指定进程替代<(...),而不是文件名。有一个类似的形式,>(...)可以用来代替命令要写入文件的文件名。


像数组一样,进程替换是bash和其他高级Shell的功能。它不是POSIX标准的一部分。


补充笔记

以下命令创建一个shell变量,而不是一个shell数组:


array=`find . -name "${input}"`

如果要创建一个数组,则需要将括号放在find的输出周围。因此,天真的,一个人可以:


array=(`find . -name "${input}"`)  # don't do this

问题在于外壳程序对的结果执行单词拆分,find因此不能保证数组的元素是您想要的。


查看完整回答
反对 回复 2019-11-12
?
白衣染霜花

如果您使用bash4或更高版本,您可以取代你使用的find有


shopt -s globstar nullglob

array=( **/*"$input"* )

通过**启用的模式globstar匹配0个或更多目录,从而允许该模式匹配当前目录中的任意深度。如果没有该nullglob选项,则模式(在参数扩展之后)将按字面意义处理,因此,如果没有匹配项,则您将拥有一个包含单个字符串而不是一个空数组的数组。


dotglob如果您想遍历隐藏的目录(如.ssh)并匹配隐藏的文件(如.bashrc),也将选项添加到第一行。


查看完整回答
反对 回复 2019-11-12
?
慕的地8271018

Bash 4.4 -d为readarray/ 引入了一个选项mapfile,因此现在可以通过以下方式解决


readarray -d '' array < <(find . -name "$input" -print0)

一种适用于任意文件名(包括空格,换行符和通配符)的方法。


从手册中(省略其他选项):


mapfile [-d delim] [array]

-d

的第一个字符delim用于终止每个输入行,而不是换行符。如果delim为空字符串,mapfile则在读取NUL字符时将终止一行。


并且readarray只是的同义词mapfile。


查看完整回答
反对 回复 2019-11-12

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信