假设我们有这个脚本
#!bin/bash
count=0
count2=0
find "$1" -type f | while read file; do
count=$(($count +1))
find "$1" -type f | while read file2; do
count2=$(($count2 +1))
done
done
echo "count: $count" # prints 0
echo "count2: $count2" # prints 0
现在让我们进行如下修改:
#!bin/bash
count=0
count2=0
find "$1" -type f | {
while read file; do
count=$(($count +1))
find "$1" -type f | {
while read file2; do
count2=$(($count2 +1))
done
}
done
echo "count: $count" # prints some number
echo "count2: $count2" # prints 0
}
我知道问题出在管道调用的子shell中。子shell中的变量只在子shell中更改,并且无法从主shell访问更改的值(或者至少与此类似)
所以我的问题是,有什么方法可以解决这个问题吗?以便count2打印其更改的结果? (除了写入和读取临时文件,或将代码更改为for循环)。 感谢。
答案 0 :(得分:1)
您可以使用流程替换来避免管道,从而创建子shell:
#!bin/bash
count=0
count2=0
while read -r file; do
((count++))
while read -r file2; do
((count2++))
done < <(find "$1" -type f)
done < <(find "$1" -type f)
echo "count: $count"
echo "count2: $count2"
答案 1 :(得分:1)
不确定。避免管道;避免子壳:
#!bin/bash
count=0
count2=0
while read file; do
count=$(($count +1))
while read file2; do
count2=$(($count2 +1))
done < <(find "$1" -type f)
done < <(find "$1" -type f)
echo "count: $count"
echo "count2: $count2"
如果你有一个管道,如你所知,你有一个隐含的子shell。但是,我们只是从文件中重定向。 <(command)
是进程替换 - 它使用给定进程的输出(或输入,如果使用>()
)创建命名管道或/ dev / fd文件句柄。然后它会扩展为文件名。
$ echo <(echo)
/dev/fd/63
因此,这个空间非常重要。这和
不一样while read; do …; done << (command)
这只是语法错误!
我们正在做的更接近于此:
find "$1" -type f > tmpfile
while read; do …; done < tmpfile
rm tmpfile
除了文件创建和清理由系统处理。
当然,如果您只想计算文件:
find "$1" -type f -exec bash 'echo $#' _ {} + # Works up to ARG_MAX
# If number of files > ARG_MAX:
sum() {
local IFS=+
bc <<< "$*"
}
sum $( find "$1" -type f -exec bash 'echo $#' _ {} + )
答案 2 :(得分:1)
如果您使用的是bash
4,则可以取消对find
和管道的调用。
#!bin/bash
count=0
count2=0
shopt -s globstar
for file in **/*; do
[[ -f $file ]] || continue
(( count++ ))
for file2 in **/*; do
[[ -f $file2 ]] || continue
(( count2++ ))
done
done
echo "count: $count" # prints some number
echo "count2: $count2" # prints 0