【问题标题】:bash while statementbash while 语句
【发布时间】:2012-02-07 22:03:37
【问题描述】:

我有 2 个不同的脚本做的基本相同:计算当前目录中的子目录:

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

谁能给我解释一下,为什么会这样?

提前致谢 亚历克斯

【问题讨论】:

  • 或者,您也可以使用find . -maxdepth 1 -type d | wc -l 来获取您的计数(尽管它也会计算当前目录)。省略 -maxdepth 1 选项以计算子目录。
  • @choroba 有正确的答案,但一般来说,我推荐count=$(find . -printf x | wc -c) - 适用于 any 文件。

标签: bash while-loop pipe


【解决方案1】:

在第一种情况下,对 c 的赋值发生在 | 之后,即在子 shell 中。您不能从子 shell 更改父 shell 中的变量。 顺便说一句,你为什么不使用let c++ 而不是反引号和表达式?

【讨论】:

  • 谢谢 - 这是否意味着 | 之后的所有内容发生在子shell中,还是仅在这种情况下?我不知道 abotu let c++ - 我是 bash 脚本的初学者
  • 不,那是一般行为。在您的第二个命令中,您没有创建新的子外壳。您使用了流程替换,因此变量保留了它的值。
  • 在 bash 中,管道中任何位置的任何 shell 命令(即在 之前或在| 之后的 之前)都将在子 shell 中执行。其他一些 shell 有点不同,详情请参阅BashFAQ #024
【解决方案2】:

如果我必须计算子目录,那么我会使用以下两个命令之一:

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

【讨论】:

    【解决方案3】:

    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"
    

    这是一种骇人听闻的方式:

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

    您可能希望将nullglobdotglob 与上述任何一个一起使用。请参阅BashFAQ/004 了解更多信息。

    关于 subshel​​l 问题,Churoba 是正确的。

    【讨论】:

      猜你喜欢
      • 2014-01-21
      • 2013-03-26
      • 2017-04-26
      • 2017-01-15
      • 1970-01-01
      • 1970-01-01
      • 2019-01-14
      • 2016-02-29
      • 2022-01-17
      相关资源
      最近更新 更多