Different exit codes - bash

I'm trying to grep for a version number from my subversion command, so that I can check we have the write subversion module loaded in a bash script.
Interactively, this is an example use:
> svn --version | head -n1 | grep -q '1.7'; echo $?
0
However, when I put this same line (and nothing else) in a script and run the script:
> ./setup_svn.sh
1
Also, the script runs noticeably faster than the interactive shell command. Does anyone have ideas of what I might be missing that explains this result?
Edit
It turns out that my interactive bash script was using the wrong svn command. Not sure exactly why, but I think that might be a question for the Unix StackExchange.
It's almost certainly to do with the module system on our workstations, running interactively I get:
> module list
Currently Loaded Modulefiles:
...
12) subversion/1.7.7
> which svn
/usr/bin/svn
> svn --version
svn, version 1.7.7 (r1393599)
...
Running in the script, I get:
> ./setup_svn.sh
Currently Loaded Modulefiles:
...
12) subversion/1.7.7
/usr/bin/svn
svn, version 1.6.17 (r1128011)
...
Further edit
It seems that if I start a new shell, I also get the same issues:
> bash
> module list
Currently Loaded Modulefiles:
...
12) subversion/1.7.7
> svn --version
svn, version 1.6.17 (r1128011)
I think I'll find out what our module system does to the environment and use that to work out what's going wrong.

I know it will not correct the issue, but I think the head command is useless. You can use the --quiet option.
$ svn --version --quiet
1.7.5
EDIT:
If it's a semicolon issue as mentioned by konsolebox, you can also use this syntax :
echo $(svn --version --quiet | grep -q '1.7')$?

It could be how the shell handles the semicolon. Try to place in two lines.
#!/bin/sh
svn --version | head -n1 | grep -q '1.7'
echo "$?"
If you're in bash also, make sure that pipefail is not enabled:
#!/bin/bash
shopt -u -o pipefail
svn --version | head -n1 | grep -q '1.7'
echo "$?"

Related

How to check if vim version 8.1+ is installed

I have the following attempt at a vim script to check to see if it is installed and if its version is recent (8+):
# Check if we have vim version 8.1+ installed
VIM_PATH=$(which vim)
VIM_VERSION=$(vim --version |grep '8.[123]')
if [ -z "$VIM_PATH" || -z "$VIM_VERSION" ]
then
...
fi
Is the above a valid script? What might be a better way to grab the version and check if
Since vim --version isn't very machine-readable, I would be tempted to try
if vim --cmd 'if v:version >= 801 | q | else | cq | fi' ; then
# vim at least 8.1
fi
which uses a snippet of vim script to do the comparison. --cmd runs a command before opening any files or running .vimrc; the cq command exits with an error status, and q exits with a success status (necessary because otherwise vim would want to edit a blank file!). | allows placing multiple vim commands on a single line, like ; in shell.

How to "hide" an executable from a bash script?

I want to test the output of a bash script when one of the executables it depends on is missing, so I want to run that script with the dependency "hidden" but no others. PATH= ./script isn't an option because the script needs to run other executables before it reaches the statement I want to test. Is there a way of "hiding" an executable from a script without altering the filesystem?
For a concrete example, I want to run this script but hide the git executable (which is its main dependency) from it so that I can test its output under these conditions.
You can use the builtin command, hash:
hash [-r] [-p filename] [-dt] [name]
Each time hash is invoked, it remembers the full pathnames of the commands specified as name arguments, so they need not be searched for on subsequent invocations. ... The -p option inhibits the path search, and filename is used as the location of name. ... The -d option causes the shell to forget the remembered location of each name.
By passing a non-existent file to the -p option, it will be as if the command can't be found (although it can still be accessed by the full path). Passing -d undoes the effect.
$ hash -p /dev/null/git git
$ git --version
bash: /dev/null/git: command not found
$ /usr/bin/git --version
git version 1.9.5
$ hash -d git
$ git --version
git version 1.9.5
Add a function named git
git() { false; }
That will "hide" the git command
To copy #npostavs's idea, you can still get to the "real" git with the command builtin:
command git --version
Since we know the program is running in bash, one solution is to - instead of "hiding" the program - emulate the behaviour of bash in this circumstance. We can find out what bash does when a command isn't found quite easily:
$ bash
$ not-a-command > stdout 2> stderr
$ echo $?
127
$ cat stdout
$ cat stderr
bash: not-a-command: command not found
We can then write this behaviour to a script with the executable name, such as git in the question's example:
$ echo 'echo >&2 "bash: git: command not found" && exit 127' > git
$ chmod +x git
$ PATH="$PWD:$PATH" git
$ echo $?
127
$ cat stdout
$ cat stderr
bash: git: command not found

Is there a way to tell RVM to use the latest version of Ruby that is at least 2.0.0?

I often do a lot of scripting in Ruby, and sometimes I run these scripts on Jenkins jobs or put them where others can run it locally.
I would love to specify in .rvmrc something like:
Use the most recent version of ruby that is installed
Unless it is less then Ruby 2, in which case fail.
That way I can depend on Ruby 2 language changes (e.g., named parameters), but without forcing the environment running the script to install a new ruby if it already has 2.0.0 or 2.1.1 or 2.1.4 installed.
You should be able to run bash commands in the .rvmrc file. So you could check for the latest version and require it and default to a 2.0.0 version if one isn't found. I am not sure what you have in mind for failing since this file gets loaded as the terminal session is started and interrupting that would not be good.
Here is an example I crafted using rbenv sine I don't have rvm installed.
RV=`rbenv versions | grep -E " 2\.\d+\.\d+\S*" | grep -o -E "2\.\d+\.\d+\S*" | sort | tail -n 1`
if [[ $RV ]]
then echo $RV
else echo "DEFAULT"
fi
This example simply outputs the highest version of 2.x.x ruby it finds else it says DEFAULT. For RVM the following could work in your .rvmrc file although I can't test it myself. I based it on output found in the docs. You might need to adjust a little.
RV=`rbenv versions | grep -E "ruby-2\.\d+\.\d+\S*" | grep -o -E "2\.\d+\.\d+\S*" | sort | tail -n 1`
if [[ $RV ]]
then rvm use $RV
else rvm use 2.0.0
fi

Run bash script when SVN remote files have changed

I'm trying to create a Bask script on Ubuntu server that should check if files where changed on a remote SVN repository. If so it should perform some tasks.
In my case run doxygen and regenerate the documentation.
I'm having trouble interpreting the svn status response.
I've been looking all week and tried several suggestion found but it is still not working. To be precise the tasks are always run no matter if their are changed files.
Here's my script so far:
#!/bin/bash
# Get the status:
svnstatus=$(svn status -u -q)
#Check for modified or new files:
#This part is not working correctly
added=$(printf "%s" "$svnstatus" | sed -n 's/[Added] *\(.*\)/\1/p')
modified=$(printf "%s" "$svnstatus" | sed -n 's/[Updated] *\(.*\)/\1/p')
if [ "x$added" != "x" -o "x$modified" != "x" ]
then
svn update
echo regenerated documentation using doxygen
fi
The main issue is with the sed part. I'm new to Ubuntu and that part is difficult for me. I copied that from a script I found on the Internet.
$svnstatus is
Status against revision: 75016
when nothing new and
* 75016 Resources/graphs/dot_tags.txt
Status against revision: 75017
when a file is changed.
Any advice is much appreciated
That sed command doesn't match the output svn status -u -q so it won't be doing anything useful.
Instead, you can use grep to check if there are any lines in the output with a * character in the 9th column, indicating a modified file.
This should work:
#!/bin/bash
# Get the status:
svnstatus=$(svn status -u -q)
# Check for modified or new files:
if echo "$svnstatus" | grep -q '^........\*'
then
svn update
echo regenerated documentation using doxygen
fi

Pipes inside backticks fail under MinGW

When I try to run some Bash scripts on a Windows XP machine using MinGW, I get the following error:
./autogen.sh: pipe error: No such file or directory
I have localised the problem to Bash lines such as the following, which have a pipe inside backticks:
__copyright="`grep Copyright ./autogen.sh | head -1`"
However, pipes not inside backticks work just fine:
grep Copyright ./autogen.sh | head -1
All the programs you expect (sh, head, grep) are available and run happily on the command line and in Bash.
What should I do to resolve this error? I cannot run most Bash build tools without it.
$ msysinfo | head -3
msysinfo-1.3: Send this to the MSYS support list:
MSYS 1.0.11(0.46/3/2) 2004-04-30 18:55 i686 unknown; targ=MINGW32
$ echo '__copyright="`grep Copyright ./autogen.sh | head -1`" && echo $__copyright' >test.sh
$ cat test.sh
__copyright="`grep Copyright ./autogen.sh | head -1`" && echo $__copyright
$ sh test.sh
# Copyright 2005, 2006, 2007, 2008 by
For this test, I copied autogen.sh from some place like... randomly... http://svn.ghostscript.com/ghostscript/tags/freetype-2.3.7/autogen.sh
Probably this means your question needs more information.
But... sometimes when I run into snarly scenarios, it can help to enclose the breaking code in ( ). Technically, also, you do not need " " around backticks, and that complicates some use, but your example does not seem problematic.
I really hate to propose the following as it seems completely unnecessary:
$ for item in `grep Copyright ./autogen.sh`;
do
__copyright="$__copyright $item";
done;
echo $__copyright
What is more weird is that your error message seems to imply autogen.sh itself generated the error as though autogen.sh was grepping itself so I did:
$ sh test.sh
__copyright="`grep Copyright ./test.sh | head -1`" && echo $__copyright
after modifying test.sh to grep itself, and even that worked.
It therefore sounds like a sequencing issue and not a backtick issue, you know, which came first, the chicken or the egg?
Is autogen.sh trying to read its own Copyright comment? One way to let comments serve as data is to wrap them in here documents:
_Copyright ()
{
cat <<-END_OF_TEXT
# Copyright 2012, me
END_OF_TEXT
}
_Copyright

Resources