2012-01-11 72 views
2

我有2个不同的脚本做基本相同:在当前目录计数子目录:的bash while语句

c=0 

ls -l | grep "^d" | while read zeile 
do 
    c=`expr $c + 1` 
    echo $c 
done 

echo "Subdirs: $c" 

c=0 

while read zeile 
do 
    c=`expr $c + 1` 
    echo $c 
done < <(ls -l | grep "^d") 

echo "Subdirs: $c" 

我的问题是,在第一个版本,“ c“在while循环结束后似乎失去了它的价值。

输出

1)

1 
2 
3 
Subdirs: 0 

2)

1 
2 
3 
Subdirs: 3 

你们谁能给我解释一下,为什么发生这种情况?

预先感谢 亚历

+0

或者,您也可以使用'find。 -maxdepth 1 -type d | wc -l'来获得你的计数(虽然它也会计算当前目录)。省略'-maxdepth 1'选项以统计子目录。 – 2012-01-11 15:19:58

+0

@choroba有正确的答案,但一般来说,我会推荐计数文件'count = $(find。-printf x | wc -c)' - 与任何*文件一起使用。 – l0b0 2012-01-12 15:36:28

回答

3

在第一种情况中,分配到c |后会发生,即,在一个子shell。您不能从子shell中更改父shell中的变量。 顺便说一句,为什么你不使用let c++而不是反引号和expr?

+1

谢谢 - 这是否意味着,在|之后的所有内容发生在一个子shell中,或只在这种情况下? 我不知道abotu让c + + - 我是一个初学者在bash脚本 – Alex 2012-01-11 14:53:34

+0

没有多数民众赞成的一般行为。在你的第二个命令中,你没有创建一个新的子shell。您使用流程替代,以便变量保留它的值。 – 2012-01-11 15:30:37

+0

在bash中,管道中任何地方的任何shell命令(即在*之后的*或*之后)都将在子shell中执行。其他一些shell有些不同,详情参见[BashFAQ#024](http://mywiki.wooledge.org/BashFAQ/024)。 – 2012-01-11 16:14:02

1

如果非要算子目录,那么我会使用这两个命令之一:

find . -regex ".\{2,\}" -maxdepth 1 -type d | wc -l 
ls -l | grep "^d" | wc -l 
0

should not use ls in that way

您应该使用for循环和glob遍历文件或目录。

for f in * 
do 
    if [[ -d $f ]] 
    then 
     ((c++)) 
    fi 
done 
echo "Subdirs: $c" 

for f in */ 
do 
    ((c++)) 
done 
echo "Subdirs: $c" 

这里有一个hackish的方式:

arr=(*/); echo "Subdirs: ${#arr[@]}" 

你可能会想使用nullglobdotglob与上述任何一项。有关更多信息,请参阅BashFAQ/004

Choroba在子外壳问题上是正确的。