2012-07-06 105 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