简体   繁体   English

在 bash 脚本中多次重用命令 output

[英]reuse command output multiple times in bash script

I have a bash script that operates several similar find commands and reads the output into variables:我有一个 bash 脚本,它运行几个类似的查找命令并将 output 读入变量:

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`

All this works as expected.所有这些都按预期工作。

Assuming the "find" command to be expensive (time wise), is there a clever way of re-using one of the results for the others?假设“查找”命令很昂贵(时间方面),是否有一种巧妙的方法可以为其他结果重新使用其中一个结果?

What I tried (and failed with) is:我尝试过(但失败了)是:

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

This doesn't work, but I hope it shows what I want to achieve.这不起作用,但我希望它显示我想要实现的目标。

It seems that putting the results into a variable spoils some format of the original output, which breaks stuff when sent again to the other commands.似乎将结果放入变量中会破坏原始 output 的某些格式,当再次发送到其他命令时会破坏内容。

Is there some clever way of achieving what I want?有什么聪明的方法可以实现我想要的吗?

EDIT编辑

I created a fully working example you could recreate.我创建了一个可以重新创建的完整工作示例。 In my working dir I have a folder "foo" with 3 files "bar1", "bar2", "bar3".在我的工作目录中,我有一个文件夹“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

results in the expected结果是预期的

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

but when the result is empty (I modified the search criteria to find nothing)但是当结果为空时(我修改了搜索条件,什么也没找到)

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

the two results differ (notice the empty result line in front of the "1")两个结果不同(注意“1”前面的空结果行)

 
1
0

And thus I thought the culprint to be the extra line break in the echo command.因此,我认为罪魁祸首是 echo 命令中的额外换行符。 Therefore I removed that (notice the "-n" in the second line):因此我删除了它(注意第二行中的“-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

which solves the problem for empty results这解决了空结果的问题

 
0
0

but now when there are results, the "wc -l" counts the wrong way so但是现在当有结果时,“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

yields in产量在

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

So the problem is one line break that I thought must have an easy resolution to avoid being different between empty and non-empty find results.所以问题是一个换行符,我认为必须有一个简单的解决方案,以避免空和非空查找结果之间的差异。 I have the feeling of missing something very simple.我有一种错过了一些非常简单的东西的感觉。

Using a variable to reuse find 's output should work.使用变量重用find的 output 应该可以工作。 Maybe there are backslashes in your filenames that get interpreted by echo (although that should not happen by default).也许您的文件名中有反斜杠会被echo解释(尽管默认情况下不应该发生这种情况)。 If so, then use printf %s "$f_list" instead.如果是这样,则使用printf %s "$f_list"代替。 But without a complete verifiable example we cannot know for sure.但如果没有完整的可验证示例,我们无法确定。

However, in this specific case you can also switch to the following command which is also safe if no file matches and safe in the very unusual case where some files have multi-line filenames.但是,在这种特定情况下,您也可以切换到以下命令,如果没有文件匹配,这也是安全的,并且在某些文件具有多行文件名的非常不寻常的情况下也是安全的。

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

An alternative would be to use a temporary file.另一种方法是使用临时文件。 That would be something like:那将是这样的:

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

rm -f $temp

Use an array to store the null delimited list returned by find -print0 | sort -z使用数组存储find -print0 | sort -z返回的null分隔列表find -print0 | sort -z : find -print0 | sort -z

#!/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]}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM