0

I have a shell script when need to run as a particular user. So I call that script as below,

su - testuser -c "/root/check_package.sh | tee -a /var/log/check_package.log" 

So after this when I check the last execution exitcode it returns always 0 only even if that script fails.

I tried something below also which didn't help,

su - testuser -c "/root/check_package.sh | tee -a /var/log/check_package.log && echo $? || echo $?"

Is there way to get the exitcode of command whatever running through su.

2
  • 1
    The tee is your problem, not su (which is not sudo). Commented Dec 7, 2016 at 16:54
  • ...which is to say: su already does correctly pass exit status through. You can easily test this yourself: Run su - testuser -c "exit 2"; echo $? Commented Dec 7, 2016 at 17:00

3 Answers 3

3

The problem here is not su, but tee: By default, the shell exits with the exit status of the last pipeline component; in your code, that component is not check_package.sh, but instead is tee.

If your /bin/sh is provided by bash (as opposed to ash, dash, or another POSIX-baseline shell), use set -o pipefail to cause the entirely pipeline to fail if any component of it does:

su - testuser -c "set -o pipefail; /root/check_package.sh | tee -a /var/log/check_package.log"

Alternately, you can do the tee out-of-band with redirection to a process substitution (though this requires your current user to have permission to write to check_package.log):

su - testuser -c "/root/check_package.sh" > >(tee -a /var/log/check_package.log
Sign up to request clarification or add additional context in comments.

Comments

2

Both su and sudo exit with the exit status of the command they execute (if authentication succeeded):

$ sudo false; echo $?
1
$ su -c false; echo $?
1

Your problem is that the command pipeline that su runs is a pipeline. The exit status of your pipeline is that of the tee command (which succeeds), but what you really want is that of the first command in the pipeline.

If your shell is bash, you have a couple of options:

  • set -o pipefail before your pipeline, which will make it return the rightmost failure value of all the commands if any of them fail
  • Examine the specific member of the PIPESTATUS array variable - this can give you the exit status of the first command whether or not tee succeeds.

Examples:

$ sudo bash -c "false | tee -a /dev/null"; echo $?
0
$ sudo bash -c "set -o pipefail; false | tee -a /dev/null"; echo $?
1
$ sudo bash -c 'false | tee -a /dev/null; exit ${PIPESTATUS[0]}'; echo $?
1

You will get similar results using su -c, if your system shell (in /bin/sh) is Bash. If not, then you'd need to explicitly invoke bash, at which point sudo is clearly simpler.

3 Comments

@CharlesDuffy and Tony. Thanks! Both of it worked charm!
Also I have some customized banner for that user and when I do su through shell script then that banner message also prints. I tried to hide that message using su - testuser -s /usr/bin/id . But some script I need to run along with arguments and If I run the same way by calling those scripts with argument in double/single quotes then its not working.
@Ravi, that sounds like a separate question (and may be more appropriate for Unix & Linux, as it's not actually a programming issue). When asking it, you might want to refer to this question if it helps provide the context.
0

I was facing a similar issue today, in case the topic is still open here my solution, otherwise just ignore it...

I wrote a bash script (let's say my_script.sh) which looks more or less like this:

### FUNCTIONS ### 
<all functions listed in the main script which do what I want...>

### MAIN SCRIPT ### calls the functions defined in the section above
main_script() { 
  log_message "START" 0
  check_env
  check_data
  create_package
  tar_package
  zip_package
  log_message "END" 0
}

main_script |tee -a ${var_log} # executes script and writes info into log file
var_sta=${PIPESTATUS[0]} # captures status of pipeline
exit ${var_sta} # exits with value of status

It works when you call the script directly or in sudo mode

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.