在 bash 脚本中多次重用命令输出

reuse command output multiple times in bash script

我有一个 bash 脚本,它运行几个类似的查找命令并将输出读入变量:

f_list=`find /foo -name bar | sort`
f_number=`find /foo -name bar | wc -l`
f_first=`find /foo -name bar | sort | head -n 1`

所有这些都按预期工作。

假设“查找”命令很昂贵(时间方面),是否有一种巧妙的方法可以将其中一个结果重新用于其他结果?

我尝试过(但失败了)的是:

f_list=`find /foo -name bar | sort`
f_number=`echo "$f_list" | wc -l`
f_first=`echo "$f_list" | head -n 1`

这行不通,但我希望它展示了我想要实现的目标。

似乎将结果放入变量会破坏原始输出的某些格式,这会在再次发送到其他命令时破坏内容。

有什么聪明的方法可以实现我想要的吗?

编辑

我创建了一个您可以重新创建的完整示例。 在我的工作目录中,我有一个文件夹“foo”,其中包含 3 个文件“bar1”、“bar2”、“bar3”。

find_result=`find ./foo -type f -iname "bar*" | sort`
find_count1=`echo "$find_result" | wc -l`
echo "$find_result"
echo $find_count1
find_count2=`find ./foo -type f -iname "bar*" | wc -l`
find ./foo -type f -iname "bar*"
echo $find_count2

结果符合预期

./foo/bar1
./foo/bar2
./foo/bar3
3
./foo/bar3
./foo/bar2
./foo/bar1
3

但是当结果为空时(我修改了搜索条件,什么也找不到)

find_result=`find ./foo -type f -iname "bor*" | sort`
find_count1=`echo "$find_result" | wc -l`
echo "$find_result"
echo $find_count1
find_count2=`find ./foo -type f -iname "bor*" | wc -l`
find ./foo -type f -iname "bor*"
echo $find_count2

两个结果不同(注意“1”前面的空结果行)

 
1
0

因此我认为罪魁祸首是 echo 命令中的额外换行符。因此我删除了它(注意第二行中的“-n”):

find_result=`find ./foo -type f -iname "bor*" | sort`
find_count1=`echo -n "$find_result" | wc -l`
echo "$find_result"
echo $find_count1
find_count2=`find ./foo -type f -iname "bor*" | wc -l`
find ./foo -type f -iname "bor*"
echo $find_count2

解决了空结果的问题

 
0
0

但现在当有结果时,“wc -l”计数错误所以

find_result=`find ./foo -type f -iname "bar*" | sort`
find_count1=`echo -n "$find_result" | wc -l`
echo "$find_result"
echo $find_count1
find_count2=`find ./foo -type f -iname "bar*" | wc -l`
find ./foo -type f -iname "bar*"
echo $find_count2

产量

./foo/bar1
./foo/bar2
./foo/bar3
2
./foo/bar3
./foo/bar2
./foo/bar1
3

所以问题是一个换行符,我认为必须有一个简单的解决方案来避免空和非空查找结果之间的差异。感觉少了一些很简单的东西。

使用变量重用 find 的输出应该可行。也许你的文件名中有反斜杠被 echo 解释(尽管默认情况下不应该发生)。如果是这样,请改用 printf %s "$f_list"。但如果没有完整的可验证示例,我们无法确定。

但是,在这种特定情况下,您也可以切换到以下命令,如果没有文件匹配,这也是安全的,并且在某些文件具有多行文件名的非常不寻常的情况下也是安全的。

shopt -s globstar dotglob nullglob
list=(/foo/**/bar)
number=${#list[@]}
first=${list[0]}

另一种方法是使用临时文件。那将是这样的:

temp=$(mktemp /tmp/prefixXXXXXXXXXXX)
find /foo -name bar | sort > $temp
f_number=`wc -l $temp`
f_first=`head -n 1 $temp`

rm -f $temp

使用数组存储 find -print0 | sort -z 返回的 null 分隔列表:

#!/usr/bin/env bash

# map null delimited output of command-group into the f_list array
mapfile -t f_list < <(find /foo -name bar -print0 | sort --zero-terminated)

# Number of entries in the f_list array
f_number=${#f_list[@]}

# First entry of the f_list array
f_first=${f_list[0]}