0

I would like to know, and how a bash script can do tasks that need to be applied one after the other.

Here is an example, I would like to install on my CentOS VPS the following softwares.

$ yum update
$ yum install libvpx-devel
$ sudo rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
$ yum install nginx
$ wget https //dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb - Chrome_stable
$ mkdir foo
$ mv Chrome_stable foo

You get the point, I have tons of commands which I must do this on a weekly basis. So, my questions is, since some installs can fail, and others need to wait for one install to be finished for the next to continue.

So, is there anyway to tell bash to wait until one install/download is finished before it goes to next command, and also to check on if previous install was a success before moving one.

1 Answer 1

4

You don't need to tell bash to wait if the processes you're executing run in the foreground (which everything you show above does) - it will block waiting for them to exit.

Once they exit, bash can examine the return code and behave differently based on that. The return code of the last subprocess is stored in the $? variable:

#!/bin/bash

yum update

if [ $? -ne 0 ]; then
    echo "Sorry, yum update had non-zero exit code, why don't we stop here?"
    exit 1
fi

yum install libvpx-devel
...

Note that the Unix convention is that a return code of 0 means a process succeeded and a return code of anything else means there were issues. The issues might be simple (e.g., grep failed to find the string you were looking for) or more complex.

Also note that you can use the && and || operators to leverage the return code in a one-liner:

yum update && echo "yum succeeded"

yum update || echo "yum failed"

Response to @Contax questions in comment:

The connection between "yum update" and "$?" is that every program that runs has an exit code that is returned to the operating system. It will generally default to 0 (success) if the program doesn't specify, but can be specified in the program (e.g., the "exit 1" shown in the script above is setting the exit code of that script to 1. In C, "return(-1)" in the main() function will cause the program to have an exit code of -1.) Bash automatically reads this exit code and stuffs it into $? for your use. Just think of it as part of the plumbing - it's behind the walls, and it makes everything work.

If you have a lot of tasks to execute, yes, this gets tedious. That's why 95% of shell scripts out there don't do any error checking and blow up in spectacular fashions when something goes wrong :) You would have to create an if [ $? -ne 0 ]; then clause for each task. If you were really adventurous you could find a way to wrap your executions into a loop and re-use the code, but that would probably be more trouble than it's worth.

The || shorthand is useful for compromising between code simplicity and error checking. As you've noticed writing an if clause for everything is a PITA, but yum update || exit 1 will cause your script to quickly and quietly bail upon that process's failure. Less friendly than taking the time to print out info and clean up, but better than continuing to run commands that are doomed to fail because an earlier step failed.

2
  • Wow, thanks for blowing my mind. But I don't see any connection between yum update and $? won't this create a problem is I have lots of tasks to execute? or do I have to create if [ $? -ne 0 ]; then after each task? Oct 10, 2014 at 13:54
  • 1
    Another option is to say set -e and then simply list the commands (as presented in the question). set -e tells the shell to exit from the script if (when) any command fails (exits with a status other than 0). Oct 10, 2014 at 22:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .