Visit Jeremy's Blog.
Go Back > Forums > Non-*NIX Forums > Programming
User Name
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.


Search this Thread
Old 04-02-2012, 12:36 AM   #1
Registered: Sep 2003
Posts: 79

Rep: Reputation: 0
Question Bash Shell program question - if error then mailx

Hey Guys

Multiple questions

Basically I am trying to write a shell script in bash which does the following

1) Does some export and zip -- this part is easy and done
2) create a folder if it does not exist
3) Move files to that folder in (2)
4) if an error happens in step (1-3) then send a mail (mailx)


What I have figured is

start if loop
start for loop for number of files
    export files
mkdir -p /location/to/store/file
mv *.files /location/to/store/file
echo "Didn't work" | mailx -s Error on `hostname`
Now this will email everytime even if there is or isin't an error..

How do i do some kind of error trapping here that if

1) export file OR mkdir OR mv fails (or any return other than 0 from what i understand)

then the echo mailx gets kicked off

Old 04-02-2012, 04:19 AM   #2
LQ Veteran
Registered: Sep 2003
Posts: 10,532
Blog Entries: 7

Rep: Reputation: 2376Reputation: 2376Reputation: 2376Reputation: 2376Reputation: 2376Reputation: 2376Reputation: 2376Reputation: 2376Reputation: 2376Reputation: 2376Reputation: 2376

$? tells you if a command succeeded or failed. If the output is 0 (zero), the command ran the way it should have, anything else points to a failure. Using $? only works when used immediately after the command you need to check. Have a look at this:
ls foobar
if [[ "$?" != "0" ]] # is $? anything but 0
  echo "oeps..."     # your code goes here...
  exit 1             # stop the script
The exit 1 makes sure your script stops running once it encounters an error.

If you need to check the success of a command multiple times you can either use the above code multiple times or make a function:
function errorHandler ()
  echo "oeps..."     # your code goes here...
  exit 1             # stop the script

ls foobar
[[ "$?" != "0" ]] &&  errorHandler  # is $? anything but 0

mv FooBar /x/y/z
[[ "$?" != "0" ]] &&  errorHandler  # is $? anything but 0
Hope this helps.
1 members found this post helpful.
Old 04-02-2012, 06:53 AM   #3
David the H.
Bash Guru
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950
You can also use any command directly in an if construct, not just the "["-type tests. The exit code is what if is checking for, after all.

if maincommand ; do
	<subcommands upon success (exit code =0)>
	<subcommands upon failure (exit code >0)>
Old 04-02-2012, 07:11 AM   #4
Nominal Animal
Senior Member
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943
I fully agree with Druuna.

Since the exit status value ($?) itself does not matter -- we are only interested if it was nonzero --, I prefer to use a bit different form of a shell function (Fatal) for this:
FatalSubject='This thing just failed, see'

function Fatal () {
    if [ $? -ne 0 ]; then
        echo -e "$@" | mailx -s "$FatalSubject" "$FatalRecipient"
        exit 1
    return 0
The idea is that you append || Fatal 'Description' after each command that should not fail. If, and only if, the left side of the || fails, the Description is e-mailed to $FatalRecipient using subject $FatalSubject :
cp -pf oldfile newfile || Fatal "Cannot copy 'oldfile' to 'newfile'."
If you want to fail unconditionally, use
false || Fatal 'Description'
since false will do nothing but fail; it does nothing but return a nonzero exit status.

Here is a real world example:

A typical operation in a script like this is to create a temporary working directory. This is how to do it so that it will be automatically deleted when the script exits, no matter why the script exits. If the temporary directory cannot be created, the script is aborted, and an error e-mail sent:
tempdir="$(mktemp -d)" || Fatal 'Cannot create a temporary directory.'

trap "rm -rf '$tempdir'" EXIT
The trap command removes the directory whenever the interpreter exits. (Because the command is in double quotes, the value of $tempdir is evaluated right then and there, when the trap is set. This means that even if you change tempdir later on, it will not affect the trap; regardless of the value of $tempdir when the script exits, the trap will always remove the original directory.)

Let us expand this example a bit further.

Let us say you wish to apply a sed operation to say all files in and under /var/lib/mystuff/. The following form requires Bash (read -rd ""), but does support all possible file names, even those containing whitespace or newlines or other weird characters:

find /var/lib/mystuff/ -type f -print0 | while read -rd "" FILE ; do

    cp -f --preserve=all "$FILE" "$tempdir/copy" || Fatal "Could not backup '$FILE'."

    sed -e 's|something|other|g' "$FILE" > "$tempdir/copy" || Fatal "Could not edit '$FILE' using sed."

    mv -f "$tempdir/copy" "$FILE" || Fatal "Could not replace '$FILE'."

The LANG and LC_ALL are used to set the POSIX aka C locale, just in case you happen to have filenames with non-UTF-8 byte sequences in them. If you use an UTF-8 locale (and most of us do), the tools will abort if they encounter a non-UTF-8 byte sequence in a file name or other string. Setting the locale to POSIX tells tools to treat all names and strings as eight-bit byte sequences.

Note that this affects the sed , too. In the POSIX locale, does not match [a-z]. In the en_US.UTF-8 locale (and all other UTF-8 locales), it does! If you need or want that behaviour, you can always just add LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 LC_CTYPE=en_US.UTF-8 before the sed command, on the same line, to change the locale only for the sed command.

The loop body will first copy the original file into the temporary directory, preserving all metadata (from ownership and mode, up to extended attributes). Ownership is only preserved if the user running the command is allowed to. This copy is done not to save the data, but to save the metadata; this happens to be the easiest way to copy all metadata.

The sed command overwrites the contents of the temporary copy. If it fails, the original file will be intact. Redirecting to the file does not change its metadata (other than size and modification timestamp).

Finally, the original file is replaced with the edited copy. If $tempdir is on the same filesystem, this is guaranteed to leave you with either the original file, or the new file, but never a broken copy. (For different filesystems, it depends on mv implementation; I believe Coreutils mv has the same guarantee across filesystems if using ext2/ext3/ext4/xfs/reiserfs.)

While the above sequence may look a bit cumbersome, it practically guarantees it will always Do The Right Thing. If it fails, the original file is kept intact. If it succeeds, only the contents of the file are changed (although actually the entire file is replaced). For example, SELinux security context, POSIX ACLs, and all extended attributes the file might have, should stay intact.

Moreover, if it fails for any reason, you will always get an e-mail message describing the reason. You could even add
        logger -p 'local.error' -i -t 'MyScript' "$@"
just before the exit 1 in the Fatal function body, to log the error message in the system log, in addition to sending an e-mail. See man logger for details on its use.

Hope this helps,
1 members found this post helpful.
Old 04-20-2012, 07:55 PM   #5
Registered: Oct 2008
Posts: 316

Rep: Reputation: 23
While I was not part of this discussion, let me say that this is exactly the information I was seeking and answered my would be question completely.

LinuxQuestions comes through again.
Thank you guys.

I needed tobe sure the script was killed should an error for any reason pop up.
# check if there is no command line argument
if [ $# -eq 0 ]
echo "You forgot the information: Month Year seperated by a space."

function errorHandler ()
  echo ".....process failed."     # your code goes here...
  exit 1             # stop the script


	cd work 
		[[ "$?" != "0" ]] &&  errorHandler;
	cp /media/VOLUMELABE/DCIM/101EKAIO/*.jpg . 
		[[ "$?" != "0" ]] &&  errorHandler;
	convert *.jpg -adjoin $MONTH-$YEAR.pdf  
		[[ "$?" != "0" ]] &&  errorHandler;
	cp $MONTH-$YEAR.pdf ../$YEAR 
		[[ "$?" != "0" ]] &&  errorHandler;
	rm *.jpg *.pdf
		[[ "$?" != "0" ]] &&  errorHandler;
	rm /media/VOLUMELABE/DCIM/101EKAIO/*.jpg 
		[[ "$?" != "0" ]] &&  errorHandler;



bash, error, mailx, shell, trap

Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
bash + mailx question Efo Linux - General 2 11-27-2011 12:17 PM
bash shell program question rsatyandra Programming 10 07-24-2011 10:15 AM
Using Bash shell when I run a program from it jimmyrp Linux - Newbie 6 05-15-2011 01:54 PM
Simple Bash Shell Program frankblack Programming 2 02-15-2003 12:59 AM
bash shell program help embsupafly Programming 7 11-27-2002 01:05 AM

All times are GMT -5. The time now is 08:18 AM.

Main Menu
Write for LQ is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration