我想计算给定目录中的所有 *bin文件。最初我使用for-loop
:
var=0
for i in *ls *bin
do
perform computations on $i ....
var+=1
done
echo $var
但是,某些目录中的文件太多,导致出现错误:Argument list too long
因此,我尝试使用管道while-loop
:
var=0
ls *.bin | while read i;
do
perform computations on $i
var+=1
done
echo $var
现在的问题是通过使用管道创建子 shell 。因此,echo $var
返回0
。
我该如何处理这个问题?
原始代码:
#!/bin/bash
function entropyImpl {
if [[ -n "$1" ]]
then
if [[ -e "$1" ]]
then
echo "scale = 4; $(gzip -c ${1} | wc -c) / $(cat ${1} | wc -c)" | bc
else
echo "file ($1) not found"
fi
else
datafile="$(mktemp entropy.XXXXX)"
cat - > "$datafile"
entropy "$datafile"
rm "$datafile"
fi
return 1
}
declare acc_entropy=0
declare count=0
ls *.bin | while read i ;
do
echo "Computing $i" | tee -a entropy.txt
curr_entropy=`entropyImpl $i`
curr_entropy=`echo $curr_entropy | bc`
echo -e "\tEntropy: $curr_entropy" | tee -a entropy.txt
acc_entropy=`echo $acc_entropy + $curr_entropy | bc`
let count+=1
done
echo "Out of function: $count | $acc_entropy"
acc_entropy=`echo "scale=4; $acc_entropy / $count" | bc`
echo -e "===================================================\n" | tee -a entropy.txt
echo -e "Accumulated Entropy:\t$acc_entropy ($count files processed)\n" | tee -a entropy.txt
4条答案
按热度按时间xtfmy6hx1#
问题在于while循环是管道的一部分。在bash管道中,管道的每个元素都在其自己的子shell ref(https://www.gnu.org/software/bash/manual/html_node/Pipelines.html)中执行。因此,在while循环终止后,while循环子shell的
var
副本被丢弃,而父级的原始var
(其值未更改)被回显。解决此问题的一种方法是使用Process Substitution,如下所示:
请查看BashFAQ/024以了解其他解决方法。
请注意,我还将
ls
替换为find
,因为这不是parsels
的好做法。kninwzqo2#
一个符合POSIX的解决方案是使用管道(p文件)。这个解决方案非常好,可移植,POSIX,但是在硬盘上写一些东西。
你的管道是硬盘上的一个文件。如果你想避免有无用的文件,不要忘记删除它。
vql8enpb3#
因此,研究通用问题,将变量从子shell while循环传递到父循环。我发现的一个解决方案是使用here-string,但这里没有。由于这有点害羞,而且我更喜欢POSIX解决方案,我发现here-string实际上只是here-document的一个快捷方式。有了这些知识,我提出了以下方法,避免了子shell;从而允许在循环中设置变量。
对于所有的复制粘贴者来说,一个重要的注意事项是,here-document是使用连字符设置的,这表示制表符将被忽略。这是为了保持布局的美观。需要注意的是,因为stackoverflow不会在“code”中呈现制表符,而是用空格替换它们。Grmbl.所以,不要因为你们喜欢空格而不是制表符,就破坏我的代码,这在这种情况下是无关紧要的!
这可能会在不同的编辑器(设置)等上中断。所以另一种选择是将它作为:
roejwanj4#
这也可以通过for循环来实现: