Run a command right before a script exits due to failure - shell

Let's say there's this script
#!/bin/zsh
python -c 'a'
which will fail since a isn't defined. Just before the shell script exits, I want to run a command, say echo bye. How can that be achieved?
Flow is to be:
Python command above fails.
bye appears in terminal.
The zsh script exits.
I'd prefer it to affect the python command as little as possible such as indent, putting it in an if block, checking its exit code etc. In real life, the command is in fact multiple commands.

In the script you posted, the fact that the shell exits is unrelated to any error. The shell would exit, because the last argument hast been executed. Take for instance the script
#!/bin/zsh
python -c 'a'
echo This is the End
The final echo will always be exeuted, independent of the python command. To cause the script to exit, when python returns a non-zero exit code, you would write something like
#!/bin/zsh
python -c 'a' || exit $?
echo Successful
If you want to exit a script, whenever the first one of the commands produces a non-zeror exit status, AND at the same time want to print a message, you can use the TRAPZERR callback:
#!/bin/zsh
TRAPZERR() {
echo You have an unhandled non-zero exit code in your otherwise fabulous script
exit $?
}
python -c 'a'
echo Only Exit Code 0 encountered

Related

Not able exit from docker container with bash script containing exit command

I'm able to exit when I enter the exit command in container environment. But if I try to run a script file having the exit command, I'm not able to exit from the container.
1.working
ubuntu#iot-docker:/repo$ exit
exit
root#iot-docker:/repo# exit
exit
ubuntu#ubuntu-***-Twr:~/shirisha/plo-***-snt-sp_u103a3$
not working
script.sh
#!/bin/bash
exit
exit
exit is not a command to exit your container, it just exits the current shell interpreter.
When you run your script, a new shell interpreter is started according to the first line of your script (here /bin/bash). When it encounters the exit command, the interpreter stops and you get back to the command line (the previous shell).
You can make this expriment:
$ bash # Starts a new shell
$ exit # Exits the new shell; we come back to the old one
exit
$
See? Running bash in command line is similar to running your script, and exiting from it brings you back to your previous shell. You didn't exit your container.
Solution:
exec script.sh param1 ... paramN
exec will replace your current shell with the command being started (script.sh). When that command exits, you will exit your container because your old shell no longer exists.
When you script a script without "sourcing" the script, the script will be started in a new subprocess. The exit works, you will finish that subprocess.
It is important to remember, that a script starts a new environment.
Look at the script example.sh
#!/bin/bash
my_value=high
cd /tmp
Call this script with
cd $HOME
my_value="low"
./example.sh
pwd
echo "My value is now ${my_value}"
Now nothing has changed: all changes in the subprocess are gone.
You can call this script with source ./example.sh (or short . ./example.sh),
and things have changed.
When you don't want to source your script, a function (in .bashrc) might help:
example() {
my_value=high
cd /tmp
}
Now you can call the function:
cd $HOME
my_value="low"
example
pwd
echo "My value is now ${my_value}"

$? from bash script command executed by TCL (open pipe) on windows returns wrong value

I've got tcl script with two ways of execution bash script:
#exec bash ./run.sh
open "|bash ./run.sh r"
The bash script is shown below:
#!/bin/bash
ls
if [ "$?" != "0" ]; then
echo "ERROR: Status failed!" > status
else
echo "Everything is OK!" > status
fi
I'm using tclsh for Windows with bash from git bash. When I use:
exec bash ./run.sh
I've got in status file:
Everything is OK!
otherwise:
open "|bash ./run.sh r"
got:
ERROR: Status failed!
Is there any possibility to correctly detect exit code when opened the tcl pipe?
You don't describe whether you get different results out of the ls part of the script. That matters; the ls command is most certainly capable of changing its behaviour according to the environment in which it is invoked. This matters because Tcl executes subprocesses (on Windows) directly using the CreateProcess() system call, rather than the various wrapped versions that Cygwin and git bash use. Other possibilities are that you're launching the script in a different directory and so on.
However, in general we'd expect a script to behave very similarly when launched via exec or via open |… r as they share a common core of functionality. The only differences are to do with how output and termination are waited for.
If you create a subprocess pipeline, by default you won't get to find out about errors from it until you close the pipeline. exec generates any errors “immediately” because it doesn't return control to you until the subprocess has terminated and all output has been read.

Writing a bash script, how do I stop my session from exiting when my script exits?

bash scripting noob here. I've found this article: https://www.shellhacks.com/print-usage-exit-if-arguments-not-provided/ that suggests putting
[ $# -eq 0 ] && { echo "Usage: $0 argument"; exit 1; }
at the top of a script to ensure arguments are passed. Seems sensible.
However, when I do that and test that that line does indeed work (by running the script without supplying any arguments: . myscript.sh) then the script does indeed exit but so does the bash session that I was calling the script from. This is very irritating.
Clearly I'm doing something wrong but I don't know what. Can anyone put me straight?
. myscript.sh is a synonym for source myscript.sh, which runs the script in the current shell (rather than as a separate process). So exit terminates your current shell. (return, on the other hand, wouldn't; it has special behaviour for sourced scripts.)
Use ./myscript.sh to run it "the normal way" instead. If that gives you a permission error, make it executable first, using chmod a+x myscript.sh. To inform the kernel that your script should be run with bash (rather than /bin/sh), add the following as the very first line in the script:
#!/usr/bin/env bash
You can also use bash myscript.sh if you can't make it executable, but this is slightly more error-prone (somebody might do sh myscript.sh instead).
Question seems not clear if you're sourcing script source script_name or . script_name it's interpreted in current bash process, if you're running a function it's the same it's running in same process, otherwise, calling a script, caller bash forks a new bash process and waits until it terminates (so running exit doesn't exit caller process), but when running exit builtin in in current bash it exits current process.

Exiting a shell script with an error

basically I have written a shell script for a homework assignment that works fine however I am having issues with exiting. Essentially the script reads numbers from the user until it reads a negative number and then does some output. I have the script set to exit and output an error code when it receives anything but a number and that's where the issue is.
The code is as follows:
if test $number -eq $number >dev/null 2>&1
then
"do stuff"
else
echo "There was an error"
exit
The problem is that we have to turn in our programs as text files using script and whenever I try to script my program and test the error cases it exits out of script as well. Is there a better way to do this?
The script is being run with the following command in the terminal
script "insert name of program here"
Thanks
If the program you're testing is invoked as a subprocess, then any exit command will only exit the command itself. The fact that you're seeing contrary behavior means you must be invoking it differently.
When invoking your script from the parent testing program, use:
# this runs "yourscript" as its own, external process.
./yourscript
...to invoke it as a subprocess, not
# this is POSIX-compliant syntax to run the commands in "yourscript" in the current shell.
. yourscript
...or...
# this is bash-extended syntax to run the commands in "yourscript" in the current shell.
source yourscript
...as either of the latter will run all the commands -- including exit -- inside your current shell, modifying its state or, in the case of exit, exec or similar, telling it to cease execution.

shell script execution successful but output has errors, how to determine error and exit main script?

I have a main script. Inside it I call other three shell scripts, A,B and C. All were successful. Exit codes are all equal to zero. However, when I looked into the output file of the first script which is A, it contains an error message. Now I want to exit the main script and not to continue running the other scripts after the script that has output error. Can anyone help me on this? Thanks!
Even if some command in your first bash script results in an error, the script as a whole may complete with exit code 0.
You can check the exit code of any individual command in your script by using the $? variable. This variable stores the exit code of the previous command. This will allow you to check for errors within the script.
The easiest way is to append || exit 1 to the statement which is throwing the error. That will cause the script to exit if the exit code of the command is 1 (i.e. an error).
So assuming you had a command sqlscript and you wanted the entire script to exit if sqlscript exited with a non-zero exit code you would do
sqlscript || exit 1
As a point of trivia, the 1 in exit 1 is not needed. A plain exit command would also exit with the exit status of the last executed command.
Which would be false (code=1) if the sqlscript command fails. If the sqlscript command succeeds, the exit code is the exit code of sqlscript. In that case, the || does not trigger and the exit command is not executed.
I have a main script. Inside it I call other three shell scripts, A,B
and C. All were successful. Exit codes are all equal to zero. However,
when I looked into the output file of the first script which is A, it
contains an error message. Now I want to exit the main script and not
to continue running the other scripts after the script that has output
error.
Since script A doesn't return an error exit code, you have to inspect its output. This is quite easy with grep provided that you have a search string which clearly identifies an error message, e. g.:
# this echo command simulates script A - it outputs "error" and exits with 0:
echo "contains an error message" >StoreKey_All.csv # assumed this output file
grep error StoreKey_All.csv && exit 1 # exit if output has error
# continue with scripts B and C
echo B

Resources