Reputation: 4974
I want to do a very simple script: just want to find the newest version of a program, say svn, on my computer. I want to load the result into a variable, say mysvn
So I make this script:
#!/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
Very simple in fact ... but it does not work under rxvt (my pseudo-linux terminal), version 2.7.10, running under XP: the final output string is foobar.
Does anybody know why I have this problem?
I have been writing some scripts for the past few months, it is the first time I encounter such a behaviour.
Note: I know how to make it work, with a few changes (just put the main lines into $() )
Upvotes: 4
Views: 3003
Reputation: 126048
The reason this occurs is that the while loop is part of a pipeline, and (at least in bash) any shell commands in a pipeline always get executed in a subshell. When you set mysvn inside the loop, it gets set in the subshell; when the loop ends, the subshell exits and this value is lost. The parent shell's value of mysvn never gets changed. See BashFAQ #024 and this previous question.
The standard solution in bash is to use process substitution rather than a pipeline:
while
...
done < <(which -a svn)
But note that this is a bash-only feature, and you must use #!/bin/bash
as your shebang for this to work.
Upvotes: 2
Reputation: 566
Here on Ubuntu:
:~$ which -a svn | while read p
> do
> version=$("$p" --version | grep 'version ' | grep -oE '[0-9.]+' | head -1)
> echo $version
> done
.
so, your version is .
, not very nice.
I tried this, and I think it's what you're looking for:
:~$ which -a svn | while read p
> do
> version=$("$p" --version | grep -oE '[0-9.]+' | head -1)
> echo $version
> done
1.7.5
Upvotes: 0