exit from running, sourcing, or pasting a series of commands in bash
1
vote
0
answers
129
views
I'm writing a script that I run directly, "source" from the bash console, or cut/paste as a sequence of commands into a console from an editor window. The script or its pasted commands may encounter an error and need to exit; when it does, I do not want to exit the console.
The problem is pasting commands into the terminal because each line is treated independently: aborting on one line will still execute the subsequent lines. I do not want to rely on external commands, only Bash.
I have come up with a way to do this, but am wondering if there's an easier/better way. Put this into a script then either run it, source, it, or paste the commands into a console window:
#!/bin/bash
# test of exit from running, sourcing, or pasting a series of commands
# return fails implies either running or pasting; if not running, then pasting
shopt -s expand_aliases
SAVEOPTS=/tmp/$$.bashopts
saveopts () {
set | egrep -v '(BASHOPTS|BASH_VERSINFO|EUID|PPID|SHELLOPTS|UID)=' >$SAVEOPTS
alias >>$SAVEOPTS
}
alias EXIT="{ echo 'exit required, terminating' ; \
return 2 >&/dev/null || \
[[ '${0}' == '${BASH_SOURCE}' ]] && exit 2; \
saveopts ; exec bash --rcfile $SAVEOPTS; }"
# usage
echo "good stuff" # commands that should pass
true || EXIT # example of a successful command
echo "more good stuff" # another good command
false || EXIT # failed command
echo "SHOULD NOT SEE THIS" # do not want this to run
I'm using this in GNU bash, version 5.2.15(1).
How it works - call EXIT
when you wish to terminate.
1. If sourcing the script, e.g., source 1.sh
, the return 2
in the alias causes the sourcing to stop.
2. If running the script directly, e.g., bash 1.sh
or just ./1.sh
, the return 2
fails and falls through to the second condition that checks whether the name of the process is the name of the script. This succeeds, resulting in an exit 2
.
3. If pasting, these first two conditions don't take effect, so instead it re-execs the current shell bringing back in the previous settings. Using exec preserves the PID of the shell. (The grep -v's are for unsettable options and is done to prevent the shell from trying to set these.)
This generally feels fragile. Is there a better way?
I'd like to have EXIT
as the command, but am open to eval something
, or a function call, or something else, as long as it's relatively short. I also prefer not to depend on external commands (which I don't have installed) such as xclip
.
*Revisions to this post:*
- Added the exec logic simplifying the entire thing
- This is a different question than another question having to do with aliases and not terminating a list of pasted commands.
Asked by Russ
(159 rep)
Jul 29, 2024, 02:53 PM
Last activity: Jul 29, 2024, 06:32 PM
Last activity: Jul 29, 2024, 06:32 PM