-1

I want a shell script to write a message depending on whether tar succeeds or fails, but this script doesn't work correctly:

TAR=$(tar -cf Archiv.tar myfolder/ myotherfolder/)
if [ ! "$TAR" = "/dev/null" ]; then
   echo "success"
else
  echo "error - no such Directory or file"
fi

What is the problem?

Warren Young
  • 3,715
  • 2
    You will have to explain what the script is supposed to do and what "doesn't work" means. I can't understand at all why you would want to print "success" if tar prints "/dev/null" and the other message otherwise. – psusi Jan 10 '16 at 23:38

2 Answers2

4

I'm not aware of a situation where tar will output /dev/null to signal an error, which is how your code attempts to detect the error. This is the correct way to check for errors:

if tar -cf Archiv.tar myfolder/ myotherfolder/
then
    echo "success"
else
    echo "error - no such Directory or file"
fi

You probably don't need the else case because tar itself will complain in that case. If your use of /dev/null was supposed to suppress tar complaints so that you can substitute your own message, then the first line should be:

if tar -cf Archiv.tar myfolder/ myotherfolder/ > /dev/null 2>&1

Notice that we're not using square brackets here. That's actually an alias for a built-in shell command called test(1) which does logical operations and returns 0 or nonzero to signal success or failure, respectively. if in turn checks for this 0/nonzero return, so in order to check for the success of a program like tar that returns nonzero on failure, you don't need to involve test or its alias [.

If you were trained on a programming language that requires some kind of punctuation surrounding the if expression so that the lack of punctuation bothers you here, you could rewrite the first line like this:

tar -cf Archiv.tar myfolder/ myotherfolder/
if [ $? = 0 ]

These two lines together do the same thing a the version above because the shell built-in variable $? holds the status code of that last program run.

This is perhaps clearer, but a bit wasteful.

Warren Young
  • 3,715
  • Thank you Warren Young! And can I "process" assign? Example: if [ $TAR = 0 ] – Jannyeis Jan 11 '16 at 00:18
  • @Jannyeis: I'm not sure what you mean. If you run tar inside $() like in your original code, you are capturing its output. So, comparing that output to 0 is also not likely to do what you want. You're interested in the exit status code here, not the text output of the program. – Warren Young Jan 11 '16 at 00:22
1

As usual there is more then one way to do what you were trying to.
This is a (maybe compact) way to do it:

#!/bin/bash
TAR_COMMAND='tar -cf Archiv.tar myfolder/ myotherfolder/ 2>/dev/null'
MSG_OK='### Work well DONE ### '   # A more common way to use a variable
MSG_ERR='### OPS IT FAILS ###  '    

$TAR_COMMAND && echo $MSG_OK || echo $MSG_ERR

Short notes

  • If you have no need to store the exit status (or the exit code) of your command you can use immediately after the operators AND, &&, and OR, || [1].
    The logic: cmd1 && cmd2, cmd2 will executed only if cmd1 exits without errors (with exit code 0). Instead with cmd1 || cmd3, cmd3 will be executed only if cmd1 will exits with an error (error code different from 0).

  • If, instead, you want to store the exit code of a command you have to do it immediately after its execution, because with the next command execution this value will be updated. It's enough a variable assignation

    mycommand               # you execute your command
    ExitCodeToUseLater=$?   # So I can use it later in the script
    # ... other stuffs ...
    [ $ExitCodeToUseLater = 0  ]  && echo "It was gone ok " 
    # ... again other stuffs ...
    [ $ExitCodeToUseLater = 0  ] || echo "# Never a time that it goes as I want"
    
  • In bash scripting, as well as in the makefiles [2a,2b], you can find a command with many options written in a variable in order to make more readable the code (as you can see above for the TAR_COMMAND variable). Writing in a shell the variable $MyVar it will be the same to write in the shell what is written inside [3]. It works in a script too. You may have to pay attention to the bash expansion and substitution rules about which you can read more from man bash.

  • /dev/null is the Null device [4], "a device file that discards all data written to it but reports that the write operation succeeded". It can be used to give an empty input to a command (</dev/null) or to pass in "absolute silence" the standard output or the standard error [5].
Hastur
  • 18,942
  • And how could you print the message and exit right after like || echo $MSG_ERR && exit -1 (which doesn't work)? – Olivier Pons May 05 '22 at 21:00
  • Did you tried {...}? Check from command line: (head /dev/urandom | tar -cf archive.tar -T - 2>/dev/null || { /bin/echo "Error" && exit 3 ;}) ; echo $? It answers me 3. But even (head /dev/urandom | tar -cf archive.tar -T - 2>/dev/null || echo "Error" && exit 3 ) ; echo $? it answers me 3. Ps> Note (...) is to execute in a subshell else when it exits it closes the terminal. – Hastur May 13 '22 at 11:12
  • Yes I tried {...} but it didn't work. It seems, from my beginner's point of view, that {...} are made to "group something to be a global output" like {...} > tt.txt or {...} | more. Maybe my understanding is not good but anyway it didn't work. – Olivier Pons May 13 '22 at 15:17
  • Strange it should. Did you remember to put also the last ; ? Did the previous examples work in your environment (hopefully a modern bash)? You can always store the exit code (ExitCodeToUseLater=$?) and use this value after as a normal variable (check examples online)... – Hastur May 13 '22 at 16:43