This question already has answers here:
Automatic exit from Bash shell script on error [duplicate]
(8 answers)
Specific man page for shell built-in commands like 'source' [duplicate]
(1 answer)
Closed 4 years ago.
I often see set -e or set -ex in dockerfiles and I was wondering what their purpose was. Recently, I've also seen set -o pipefail, and I have no idea what it does. I tried man set to see if there was any manual description, but there wasn't any and I am resorting to ask here.
You can find the full list here:
https://ss64.com/bash/set.html
-e
Exit immediately if a simple command exits with a non-zero status, unless the command that fails is part of an until or while loop, part of an if statement, part of a && or || list, or if the command's return status is being inverted using !. -o errexit
-x
Print a trace of simple commands and their arguments after they are expanded and before they are executed. -o xtrace
-o pipefail
If set, the return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands in the pipeline exit successfully. This option is disabled by default.
Related
This question already has answers here:
What is the difference between double-ampersand (&&) and semicolon (;) in Linux Bash?
(4 answers)
Closed 2 years ago.
I've been doing lots of Linux based stuff with my time and I know that the ; is used to separate commands, and && runs command after the previous one is done.
But if anyone more knowledgeable then me can explain the difference between the two, that would be nice.
Here's a simple example:
whoami ; hostname
whoami && hostname
; will execute the second command whether or not the first returns without error.
&& is the bash AND logical operator, and will execute the second command only if the first returns succesfully without error.
The success of a command is determined by its exit status.
This question already has answers here:
is it possible to use variables in remote ssh command?
(2 answers)
Closed 4 years ago.
in a bash script i try to do:
ssh -n $username#server2 "rm ${delete_file}"
but always get the error:
rm: missing operand
when I
> echo $delete_file
> /var/www/site/myfile.txt
I get the correct path.
What am i doing wrong?
Could it be that in your case, $delete_file is set on the remote host and not on your current machine?
If you want $delete_file to be expanded on the remote side (i.e., after ssh'ing into server2), you have to use single quotes:
ssh -n $username#server2 'rm ${delete_file}'
Other than that, do you set the value of delete_file in the same script (before ssh'ing), or before invoking your script? If latter is the case, it can't work: Variables are not propagated to scripts called by the current script/session.
You could do the following about it:
delete_file=<your-value> ./ssh-script
or:
delete_file=<your-value>
export delete_file
./ssh-script
As it turns out this last option was the problem, let me elaborate on best practices:
Better than setting environment variables would be the usage of positional parameters.
#!/bin/bash
# $1: file to delete
delete_file=${1:?Missing parameter: which file for deletion?}
ssh -n $username#server2 "rm ${delete_file}"
Usage of the script is now as simple as:
./ssh-script <your-file-for-deletion>
This way, you don't have to remember which variable is exactly expected by the script when calling it - simply call the script with a positional parameter.
As a bonus, the example uses parameter expansion to check for not-set or empty parameters:
delete_file=${1:?Missing parameter: which file for deletion?}
Whenever $1 happens to be unset or empty, the scripts exits immediately with exit code 1 and prints given message to stderr.
This question already has an answer here:
How to prefill command line input
(1 answer)
Closed 6 years ago.
I'm trying to write a BASH script to output a partially completed command which I can then add parameters to, hit ENTER and then run. I want this to be implemented completely in BASH.
e.g.
~> ./test.sh
~> ls -al <CURSOR POSITION HERE>
The only variable I've found that's close is the PROMPT_COMMAND variable, which when set inside test.sh to 'ls -al', will then immediately execute it once the script has exited.
Is there a way to stop the immediate execution, so I can add, say, *.log?
How about
read -e -p"$PWD> " -i"ls -al " cmd; eval "$cmd"
This question already has answers here:
Exit Shell Script Based on Process Exit Code [duplicate]
(9 answers)
Is it possible to get the exit code from a subshell?
(3 answers)
Closed 8 years ago.
I have a simple ruby script which uses the abort function to exit with a non-zero exit code
#!/usr/bin/env ruby
puts "I ran"
abort "Exiting"
How can I capture the exit code when I execute this command in bash?
I have tried exit_code=./test or exit_code=ruby test to no avail.
Thanks
Try this:
./test
echo $?
The special shell variable $? contains the exit code of the last terminated program.
It does not matter whether your program is a ruby program. All Unix programs have an exit code which is handled alike in the starting shell.
The exit code of the last program that ran is stored in $?
You find the exit code from the previously executed command in the variable $?.
This question already exists:
“set -e” in a function [duplicate]
Closed 7 years ago.
Note: If you are looking for a workaround because set -e does not work in a function, please go to “set -e” in a function. This question is about why it does not work as expected.
When the following is run on GNU bash, version 4.1.5(1)-release :
set -ex
PS4=' ${FUNCNAME[0]}: $LINENO: '
function f() {
set -e
false
echo $#
}
! f why does it display ? It should stop because of -e
f
It displays
: 11: f why does it display '?' It should stop because of -e
f: 6: set -e
f: 7: false
f: 8: echo why does it display '?' It should stop because of -e
why does it display ? It should stop because of -e
: 12: f
f: 6: set -e
f: 7: false
I expect it to never go past the false, because -e means "exit when a command has a non zero exit status". I am aware that -e has a tricky behavior, as explained in http://mywiki.wooledge.org/BashFAQ/105 but I would like to understand what happens in this specific case. I am using -e and it proved most helpful in many very simple scenarios. This scenario is a little more tricky but if it can be explained I may use -e instead adding || exit 1 after each line.
While trying to solve a similar problem, I read the man page for set -e:
-e errexit
Exit immediately if a simple command exits with a non-zero
status, unless the command that fails is part of an until or
while loop, part of an if statement, part of a && or || list,
or if the command's return status is being inverted using !.
Note the last bit about the return status being inverted. I guess the logical negation of function f must have an effect on the behaviour of set -e within that function.
Here's from the trap section of man bash (my emphasis):
If a sigspec is ERR, the command arg is executed whenever a simple command has a non-zero exit status, subject to the following conditions. The ERR trap is not executed if the failed command is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of a command executed in a && or || list, or if the command's return value is being inverted via !. These are the same conditions obeyed by the errexit option.
So ! command effectively disables the ERR trap inside command. I guess the reasoning is that you might not want a command exiting early if you are "kinda explicitly" checking the exit code after running it with !. Looks like bad design, since it can be used to effectively disable safeguards pretty much anywhere.
I can't precisely answer the why, but I found this snippet here:
On a slightly related note, by default bash takes the error status of the last item in a pipeline, which may not be what you want. For example, false | true will be considered to have succeeded. If you would like this to fail, then you can use set -o pipefail to make it fail.
And by updating your script as such:
function f() {
echo $SHELLOPTS
set -e
set -o pipefail
false
echo "$#"
}
It seems to behave as you expect.
So my best guess for "why" (probably the same as yours by now), is that the ! causes the function to be handled in some sort of "pipe" mode. Again... why ! means 'pipe', I guess I don't really know. Maybe a better bash expert can answer that part for us.