Bash可变范围


87

请向我解释为什么最后一个“回声”声明为空?我希望它在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手册页并没有显示给我。

  0

你在哪里初始化XCODE到可以递增的东西? 23 9月. 082008-09-23 21:57:56

  0

我试图在代码的顶部抛出一个“XCODE = 0”,在while语句之外 23 9月. 082008-09-23 21:59:21

  0

没有死锁,它适用于我。 #!/ bin/bash for i in 1 2 3 4 5;做 echo $((++ XCODE)) done echo“fin:”$ XCODE 我认为您的问题与变量范围界定无关,并且与此时发生的事情无关。 23 9月. 082008-09-23 22:08:23

  0

同意..它似乎与“while read”循环有关? 23 9月. 082008-09-23 22:11:27

91

因为你进入管道while循环,创建一个子shell来运行while循环。 现在这个子进程拥有自己的环境副本,并且不能将任何 变量传递回其父级(如同在任何unix进程中一样)。

因此,您需要进行重组,以便不进入循环。 或者,你可以运行一个函数,例如回显你想要从子进程返回的值 。

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

  0

有道理..谢谢。看起来功能是为我走的路。 23 9月. 082008-09-23 22:36:03

+1

这只是回答了我用bash脚本编写的许多看似随机的问题。 27 1月. 152015-01-27 14:29:10

  0

这个完美的回答使我感到非常困扰,并解释了我们CI系统中一个非常奇怪的行为。 06 4月. 172017-04-06 08:29:48


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

当这样做时,我现在得到一个“0”来打印最后的回声。但是我希望这个值是1而不是零。另外,为什么使用导出?我认为这迫使它进入环境? 23 9月. 082008-09-23 22:09:59


93

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

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

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

或许

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

辉煌。我之前没有看过<<语法,所以必须阅读它,但这是一种享受。让输入命令结束而不是开始感觉很奇怪,但它起作用。 31 10月. 082008-10-31 19:32:03

+3

我也不知道'<(command)'语法,这为我节省了很多时间和头痛。给你一个很大的+1先生:) 30 1月. 132013-01-30 12:29:39

+26

对于那些对整个<()语法是什么感到困惑的人(像我一样),它被称为“流程替换”,上面详细介绍的具体用法可以是看到这里:http://mywiki.wooledge.org/ProcessSubstitution 19 2月. 132013-02-19 14:53:46

  0

*谢谢*这正是我正在寻找! 04 4月. 142014-04-04 03:37:17


0

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

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

3

还有一个选项:

#!/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

  0

我收到一个错误:./scraper.sh:line 111:xsel:command not found ./scraper.sh:line 114:xsel:command not found 19 4月. 162016-04-19 01:57:49

  0

@ 3kstc显然,安装xsel。此外,你可以使用xclip,但它的使用有点不同。 这里的主要观点:第一,你把输出放入一个剪贴板(其中3个在linux中),第二 - 你从那里抓取它并发送到stdout。 09 5月. 162016-05-09 20:43:39


4

这应该工作以及(因为回声,虽然在同一子shell):

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

0

我身边这让我在做的时候我自己的小杜:

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,但是我把它变成了整个()而不是它本身,这避免了这个问题。