【问题标题】:Bash variable scopeBash 变量范围
【发布时间】:2010-09-12 13:21:00
【问题描述】:

请解释一下为什么最后的echo 语句是空白的?我希望 XCODE 在 while 循环中增加到 1:

#!/bin/bash
OUTPUT="name1 ip ip status" # normally output of another command with multi line output

if [ -z "$OUTPUT" ]
then
        echo "Status WARN: No messages from SMcli"
        exit $STATE_WARNING
else
        echo "$OUTPUT"|while read NAME IP1 IP2 STATUS
        do
                if [ "$STATUS" != "Optimal" ]
                then
                        echo "CRIT: $NAME - $STATUS"
                        echo $((++XCODE))
                else
                        echo "OK: $NAME - $STATUS"
                fi
        done
fi

echo $XCODE

我尝试使用以下语句而不是 ++XCODE 方法

XCODE=`expr $XCODE + 1`

而且它也不会在 while 语句之外打印。我想我在这里遗漏了一些关于变量范围的东西,但是 ol' 手册页没有向我显示它。

【问题讨论】:

  • 你在哪里将 XCODE 初始化为可以递增的东西?
  • 我试图在代码的顶部,在 while 语句之外抛出一个“XCODE=0”
  • 没有杂物,它对我有用。 #!/bin/bash for i in 1 2 3 4 5; do echo $((++XCODE)) done echo "fin:" $XCODE 我认为您的问题与变量范围无关,而与当时发生的一切有关。
  • 同意.. 似乎与“while read”循环有关?
  • 有一个关于此的 Bash 常见问题解答:mywiki.wooledge.org/BashFAQ/024

标签: bash scope pipe


【解决方案1】:
 #!/bin/bash
 OUTPUT="name1 ip ip status"
+export XCODE=0;
 if [ -z "$OUTPUT" ]
----

                     echo "CRIT: $NAME - $STATUS"
-                    echo $((++XCODE))
+                    export XCODE=$(( $XCODE + 1 ))
             else

echo $XCODE

看看这些改变是否有帮助

【讨论】:

  • 执行此操作时,我现在得到一个“0”来打印最后一个 echo 语句。但是我希望该值是 1 而不是零。还有,为什么要使用export?我认为这会迫使它进入环境?
【解决方案2】:

因为您是通过管道进入 while 循环,所以会创建一个子 shell 来运行 while 循环。

现在这个子进程有自己的环境副本,不能通过任何 变量返回其父级(就像在任何 unix 进程中一样)。

因此,您需要进行重组,以免进入循环。 或者,您可以在函数中运行,例如,echo 您的值 希望从子流程中返回。

http://tldp.org/LDP/abs/html/subshells.html#SUBSHELL

【讨论】:

  • 这只是回答了我在使用 bash 脚本时遇到的许多看似随机的问题。
  • 这个完美的答案让我非常沮丧,并解释了我们 CI 系统中一个非常奇怪的行为。
【解决方案3】:

问题在于,与管道放在一起的进程是在子 shell 中执行的(因此有自己的环境)。 while 内发生的任何事情都不会影响管道外的任何内容。

你的具体例子可以通过重写管道来解决

while ... do ... done <<< "$OUTPUT"

或许

while ... do ... done < <(echo "$OUTPUT")

【讨论】:

  • 对于那些对整个 mywiki.wooledge.org/ProcessSubstitution
  • 流程替换是每个人都应该经常使用的东西!它非常有用。我每天都在做类似vimdiff &lt;(grep WARN log.1 | sort | uniq) &lt;(grep WARN log.2 | sort | uniq) 的事情。考虑到您可以一次使用多个并将它们视为文件......可能性!
  • 我遇到了这个确切的问题,重构管道以保存第一阶段的输出并像这样编写非常简单。非常感谢您为我节省了数小时的研究和实验时间。
【解决方案4】:

另一种选择是将结果从子 shell 输出到文件中,然后在父 shell 中读取。像

#!/bin/bash
EXPORTFILE=/tmp/exportfile${RANDOM}
cat /tmp/randomFile | while read line
do
    LINE="$LINE $line"
    echo $LINE > $EXPORTFILE
done
LINE=$(cat $EXPORTFILE)

【讨论】:

    【解决方案5】:

    另一种选择:

    #!/bin/bash
    cat /some/file | while read line
    do
      var="abc"
      echo $var | xsel -i -p  # redirect stdin to the X primary selection
    done
    var=$(xsel -o -p)  # redirect back to stdout
    echo $var
    

    编辑: 在这里,xsel 是一个要求(安装它)。 或者,您可以使用 xclip: xclip -i -selection clipboard 代替 xsel -i -p

    【讨论】:

    • 我收到一个错误:./scraper.sh:第 111 行:xsel:找不到命令。/scraper.sh:第 114 行:xsel:找不到命令
    • @3kstc 显然,安装 xsel。此外,您可以使用 xclip,但它的用法有点不同。这里的要点:第一,您将输出放入剪贴板(其中 3 个在 linux 中),第二 - 您从那里抓取它并发送到标准输出。
    【解决方案6】:

    这应该也可以(因为 echo 和 while 在同一个子shell中):

    #!/bin/bash
    cat /tmp/randomFile | (while read line
    do
        LINE="$LINE $line"
    done && echo $LINE )
    

    【讨论】:

      【解决方案7】:

      我在制作自己的小杜时解决了这个问题:

      ls -l | sed '/total/d ; s/  */\t/g' | cut -f 5 | 
      ( SUM=0; while read SIZE; do SUM=$(($SUM+$SIZE)); done; echo "$(($SUM/1024/1024/1024))GB" )
      

      关键是我用 ( ) 制作了一个包含我的 SUM 变量和 while 的子 shell,但我通过管道进入整个 ( ) 而不是 while 本身,这避免了问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多