Get return code of ssh command in bash - bash

I need to get the return/error code of an ssh command in my bash script. The command uses applescript to move a file on the remote machine to the trash. This is part of a larger script:
ssh $login "bash -s" <<-EOF
error=(osascript -e "tell application \"Finder\" to move POSIX file \"$remote_filepath\" to trash");
[[ -n "$error" ]] && { echo -e "\nCannot move file to trash on remote mac"; exit 1; };
EOF
# echo $?; exit
[[ $? -ne 0 ]] && exit 1
# more code ...
My aim is to have the ssh command exit with code 1 if the osascript fails, so I can catch the error and abort the rest of the script.
The ssh runs successfully, the file is indeed moved to the trash. Apparently osascript runs fine, because the error message is not shown. Still, the ssh return code is 1 (I checked it with the echo $? statement. This is where I'm stuck. I'd appreciate any insight on what's wrong here.

The problem is that the [[ -n "$error" ]] command sets the error code to 1. You need to use the negation of that test. Try:
[[ -z "$error" ]] || { echo -e ...

After all the problems with osascript not returning a real error code I decided to just check if the file was moved at all, like this:
# move file to trash on remote mac
ssh $login "bash -s" <<-EOF
osascript -e "tell application \"Finder\" to move POSIX file \"$remote_filepath\" to trash" > /dev/null;
EOF
[[ ! -e "$remote_filepath" ]] || { printf "\nCannot move file to trash on remote mac" && exit 1; }
Just seems simpler and easier to maintain for me. Thanks everyone for the input!

Related

Exit if in a script, do not exit if using a terminal/tty

If the user is entering commands in a terminal, I want to echo an error statement, but I do not want the terminal to close, so I have this:
if [[ "$fle" =~ [^a-zA-Z0-9] ]]; then
echo "quicklock: lockname has invalid chars - must be alpha-numeric chars only."
if [[ -t 1 ]]; then
# if we are in a terminal just return, do not exit.
return 1;
else
exit 1;
fi
fi
however the if [[ -t 1 ]]; then does not seem to work, the terminal window I am using just closes immediately, so I think exit 1 is being called.
The -t flag checks if any of the standard file descriptors are open, and specifically [ -t 1 ] will represent if the STDOUT is attached to tty, so when running from the terminal, it will always assert this condition as true.
Also the return keyword is applicable only when running a function to break out of it instead of terminating the shell itself. Your claim of terminal window closing because of hitting exit 1 when running from script, could happen only if you source the script, (i.e. in the same shell) and will not happen if you execute the script in a sub-shell.
You can use a construct for a no-action in scripts by just doing : in the if condition as
if [[ -t 1 ]]; then
# if we are in a terminal just return, do not exit.
:
Also -t is defined by POSIX because of which you can do just [ -t 1 ].
This is actually what ended up working for me:
function on_conditional_exit {
if [[ $- == *i* ]]; then
# if we are in a terminal just return, do not exit.
echo -e "quicklock: since we are in a terminal, not exiting.";
return 0;
fi
echo -e "quicklock: since we are not in a terminal, we are exiting...";
exit 1;
}
the test is to see if we are in terminal or in a script somewhere...if we are interactive, we are in a terminal..

Has my bash script crashed?

I have a bash shell script, that should:
1) check for the existence of a file
2) If file exists exit script, otherwise create file
3) Set off a process
4) Check process has run correctly - and send result to a log file
5) Delete file
6) Exit script
if [ -f $PROPERTIES_HC ]
then
# lockfile/propertiesfile exists so exit the script
log --------- lockfile exists so operation cancelled at `date` ---------
exit 1
else
# no lockfile/propertiesfile so continue
# create the lockfile/propertiesfile
input="./$PROPERTIES_VAR"
while IFS= read -r line || [ -n "$line" ]; do
eval "echo $line" >> $PROPERTIES_HC
done < $PROPERTIES_VAR
#Run Process
RUN_MY_PROCESS --overridefile $PROPERTIES_HC >> $LOG_FILE
#Check Process Ran Okay
if [ "$?" = "0" ]; then
echo "RAN WITHOUT ERROR" >> $LOG_FILE
else
echo "SOME ERROR!" >> $LOG_FILE
fi
# Remove the lockfile/propertiesfile
rm -rf $PROPERTIES_HC
fi
This script seemed to have been running fine, however recently I came across a situation where the "RUN_MY_PROCESS" element of the script failed, and the script seems to have simply exited leaving the lockfile in place.
As I understand it unless I set something like #!/bin/sh -e, the script should run on regardless of errors. Have I misunderstood how shell scripts/shell error handling work (I am new to this!), or is it that my shell script has crashed itself - hence it didn't finish running?
Thanks in advance for any help.
The proper way to handle errors inside your script (i.e. errors that cause your script to crash) is through traps.
You could modify your script as follow :
if [ -f $PROPERTIES_HC ]
#your regular script here
#...
#Run Process
trap 'echo "SOME ERROR" >> $LOG_FILE && rm -rf $PROPERTIES_HC' ERR
RUN_MY_PROCESS --overridefile $PROPERTIES_HC >> $LOG_FILE
#rest of your script here
#....

Bash file script escaping user input

This bash script when run on Mac terminal, it needs to ask for user input, then it needs to check if a a string "PLACEHOLDER_BACKEND_NAME="user-input" exists in a given file and if not it should exit the script.
echo -e "${YELLOW}enter app name${WHITE}"
read name
line=grep $name /path/to/file/entrypoint.sh
if [[ line != "PLACEHOLDER_BACKEND_NAME=\"$name\"" ]] ; then
exit 1
fi
It needs much tuning as I am not very familiar with bash scripts. any suggestions? thx
Your code needs a little tweaking:
echo -e "${YELLOW}enter app name${WHITE}"
read -r name
if ! grep -q PLACEHOLDER_BACKEND_NAME="\"$name\"" /path/to/file/entrypoint.sh; then
exit 1
fi

Simple bash script for starting application silently

Here I am again. Today I wrote a little script that is supposed to start an application silently in my debian env.
Easy as
silent "npm search 1234556"
This works but not at all.
As you can see, I commented the section where I have some troubles.
This line:
$($cmdLine) &
doesn't hide application output but this one
$($1 >/dev/null 2>/dev/null) &
works perfectly. What am I missing? Many thanks.
#!/bin/sh
# Daniele Brugnara
# October, 2013
# Silently exec a command line passed as argument
errorsRedirect=""
if [ -z "$1" ]; then
echo "Please, don't joke me..."
exit 1
fi
cmdLine="$1 >/dev/null"
# if passed a second parameter, errors will be hidden
if [ -n "$2" ]; then
cmdLine="$cmdLine 2>/dev/null"
fi
# not working
$($cmdLine) &
# works perfectly
#$($1 >/dev/null 2>/dev/null) &
With the use of evil eval following script will work:
#!/bin/sh
# Silently exec a command line passed as argument
errorsRedirect=""
if [ -z "$1" ]; then
echo "Please, don't joke me..."
exit 1
fi
cmdLine="$1 >/dev/null"
# if passed a second parameter, errors will be hidden
if [ -n "$2" ]; then
cmdLine="$cmdLine 2>&1"
fi
eval "$cmdLine &"
Rather than building up a command with redirection tacked on the end, you can incrementally apply it:
#!/bin/sh
if [ -z "$1" ]; then
exit
fi
exec >/dev/null
if [ -n "$2" ]; then
exec 2>&1
fi
exec $1
This first redirects stdout of the shell script to /dev/null. If the second argument is given, it redirects stderr of the shell script too. Then it runs the command which will inherit stdout and stderr from the script.
I removed the ampersand (&) since being silent has nothing to do with running in the background. You can add it back (and remove the exec on the last line) if it is what you want.
I added exec at the end as it is slightly more efficient. Since it is the end of the shell script, there is nothing left to do, so you may as well be done with it, hence exec.
& means that you're doing sort of multitask whereas
1 >/dev/null 2>/dev/null
means that you redirect the output to a sort of garbage and that's why you don't see anything.
Furthermore cmdLine="$1 >/dev/null" is incorrect, you should use ' instead of " :
cmdLine='$1 >/dev/null'
you can build your command line in a var and run a bash with it in background:
bash -c "$cmdLine"&
Note that it might be useful to store the output (out/err) of the program, instead of trow them in null.
In addition, why do you need errorsRedirect??
You can even add a wait at the end, just to be safe...if you want...
#!/bin/sh
# Daniele Brugnara
# October, 2013
# Silently exec a command line passed as argument
[ ! $1 ] && echo "Please, don't joke me..." && exit 1
cmdLine="$1>/dev/null"
# if passed a second parameter, errors will be hidden
[ $2 ] && cmdLine+=" 2>/dev/null"
# not working
echo "Running \"$cmdLine\""
bash -c "$cmdLine" &
wait

Shell scripting: die on any error

Suppose a shell script (/bin/sh or /bin/bash) contained several commands. How can I cleanly make the script terminate if any of the commands has a failing exit status? Obviously, one can use if blocks and/or callbacks, but is there a cleaner, more concise way? Using && is not really an option either, because the commands can be long, or the script could have non-trivial things like loops and conditionals.
With standard sh and bash, you can
set -e
It will
$ help set
...
-e Exit immediately if a command exits with a non-zero status.
It also works (from what I could gather) with zsh. It also should work for any Bourne shell descendant.
With csh/tcsh, you have to launch your script with #!/bin/csh -e
May be you could use:
$ <any_command> || exit 1
You can check $? to see what the most recent exit code is..
e.g
#!/bin/sh
# A Tidier approach
check_errs()
{
# Function. Parameter 1 is the return code
# Para. 2 is text to display on failure.
if [ "${1}" -ne "0" ]; then
echo "ERROR # ${1} : ${2}"
# as a bonus, make our script exit with the right error code.
exit ${1}
fi
}
### main script starts here ###
grep "^${1}:" /etc/passwd > /dev/null 2>&1
check_errs $? "User ${1} not found in /etc/passwd"
USERNAME=`grep "^${1}:" /etc/passwd|cut -d":" -f1`
check_errs $? "Cut returned an error"
echo "USERNAME: $USERNAME"
check_errs $? "echo returned an error - very strange!"

Resources