2012-07-06 87 views
3

我想做一个非常简单的脚本:只想在我的计算机上找到最新版本的程序svn。我想要的结果装载到一个变量,说mysvnBash - 对变量的赋值错误

所以我有这样的脚本:


#!/bin/sh 

mysvn="foobar" 
best_ver=0 
which -a svn | while read p 
do 
    version=$("$p" --version | grep 'version ' | grep -oE '[0-9.]+' | head -1) 
    if [[ "$version" > "$best_ver" ]] 
    then 
     best_ver=$version 
     mysvn="$p" 
    fi 
    echo $mysvn 
done 

echo $mysvn 

其实很简单......但它并不下的rxvt工作(我的伪Linux终端) ,版本2.7.10,在XP下运行:最终的输出字符串是foobar。

有人知道我为什么有这个问题吗?

我过去几个月一直在写一些脚本,这是我第一次遇到这样的行为。

注:我知道如何使它工作,有几个变化(只是把主线到$())

+0

尝试做'temp = $(which -a svn)'然后'在$ temp中为p'我认为这个管道是你的问题,但是现在没有办法测试它。 – 2012-07-06 14:38:37

+1

@izomorphius:把它写成解决方案。问题的确是管道导致while循环在子shell中执行,所以对'mysvn'的任何赋值对于该shell都是本地的。 – chepner 2012-07-06 14:53:52

回答

2

发生这种情况的原因是,while循环管道的一部分,和(至少在bash)任何shell管道中的命令总是在子shell中执行。当你在循环中设置mysvn时,它会在子shell中设置;当循环结束时,子shell将退出并且此值将丢失。父shell的mysvn值永远不会改变。请参阅BashFAQ #024this previous question

在bash标准的解决方案是使用进程替换,而不是管道:

while 
... 
done < <(which -a svn) 

但是请注意,这是一个只有bash的特征,你必须使用#!/bin/bash为您认领了这工作。

+0

这被称为“过程替代”。 “命令替换”看起来像'$()'。 Zsh支持进程替换,但它(和ksh93)在某些事件被传入'while'时不会创建子shell。 Ksh93似乎不支持将进程替换重定向到“完成”或其他内置函数。 Bash 4.2有'shopt -s lastpipe',在这种情况下可以阻止子shell。 – 2012-07-06 16:05:02

+0

@丹尼斯威廉姆森:谢谢;现在修好。 – 2012-07-06 16:09:21

+0

谢谢,你的答案是有价值的。我现在看到为什么我的脚本无法正常工作。 – Bentoy13 2012-07-09 06:54:56

0

这里在Ubuntu:

:~$ which -a svn | while read p 
> do 
> version=$("$p" --version | grep 'version ' | grep -oE '[0-9.]+' | head -1) 
> echo $version 
> done 
. 

这样,你的版本是. , 不大好。

我想这一点,我认为这是你在找什么:

:~$ which -a svn | while read p 
> do 
> version=$("$p" --version | grep -oE '[0-9.]+' | head -1) 
> echo $version 
> done 
1.7.5