Looking at correcting an issue in /etc/init.d/hostapd on Debian. However, I have no clue what this line of code does nor how it works
[ -n "$DAEMON_CONF" ] || exit 0
In searching online for bash tutorials, I've never seen anyone do this
When I run the code, my shell window closes (because $DAEMON_CONF is not set to anything). If I change the code to
[ -n "not empty" ] || exit 0
my console window does not close.
so, -n evaluates to true, and or'ed with exit 0, is what?
If the expression in [] returns false, do the thing after the or || (and exit 0). Otherwise, it will short circuit and the next statement will be evaluated.
[ is and alternate name for the command test. You can learn about the parameters/flags whatnot by looking at test's manpage:
man test
You'll see for -n:
-n STRING
the length of STRING is nonzero
Furthemore || means OR. So if the test command returns False then the stuff after the || will be executed. If test returns true, then it won't be executed.
Written out your command says: "If the variable $DAEMON_CONF lacks a value, then exit with return code 0"
The longhand version would be something like:
if test ! -n "$DAEMON_CONF"; then
exit 0
fi
[ -n "$DAEMON_CONF" ] || exit 0
It's an unnecessary double negative. This would do the same thing:
[ -z "$DAEMON_CONF" ] && exit 0
Or it could be done without any flag:
[ "$DAEMON_CONF" ] || exit 0
It checks if the environment variable is defined, if $DAEMON_CONF is not present the it will exit with 0 code, a better code would be.
[ -n "$DAEMON_CONF" ] || echo "exiting as DAEMON_CONF is not set" && exit 1
Related
I have the following unix shell script, in which i have two integer
variables namely a and b.
If a is greater then or equal to b then shell script should exit with returning 0.
Else it should exit with returning 1.
My try:
Script: ConditionTest.sh
#!/bin/sh
a=10
b=20
if [ $a -ge $b ]
then
exit 0
else
exit 1
fi
....
....
....
Running Script:
$ ./ConditionTest.sh
$
Note: I am not getting any return value after executing the file.
The shell puts the exit status of the last command in the variable ?.
You could simply inspect it:
mycommand
echo $?
... or you could use it to do something else depending on its value:
mycommand && echo "ok" || echo "failed"
or alternatively, and slightly more readable:
if mycommand; then
# exit with 0
echo "ok"
else
# exit with non-zero
echo "failed"
if
Your script looks fine; you did everything right.
#!/bin/sh
a=10
b=20
if [ $a -ge $b ]
then
exit 0
else
exit 1
fi
So here's where we run it and check the return value:
$ sh test.sh
$ echo $?
1
$
10 is not greater than or equal to 20.
Another way to test it would be like this:
$ sh test.sh && echo "succeeded" || echo "failed"
failed
As noted in the comments, you should also quote your variables, always:
if [ $a -ge $b ]
Should be:
if [ "$a" -ge "$b" ]
To add to the previous answers, the key idea you should understand is that every program provides a number when exiting. That number is used as a way to report if the command has completed its operation successfully, and if not, what type of error has occurred.
Like mentioned, the exit code of the last command executed can be accessed with $?.
The reason nothing was printed by your script, is that your script returned 1, but the exit code of a command is not printed. (This is analogous to calling a function, you get a return value from the function but it's not printed)
I have a monitor shell script that does effectively monitor and keep a process running. But it often fails in the sense that it starts a second, third or more instance of the process. I have also seen the pgrep command (pgrep -n -f wx_nanoserver) return the wrong pid at the command line...
Here's my script:
#!/bin/bash
check_process() {
# echo "$ts: checking $1"
[ "$1" = "" ] && return 0
[ `pgrep -n -f $1` ] && return 1 || return 0
}
while [ 1 ]; do
# timestamp
ts=`date +%T`
NOW=`date +"%Y%m%d-%H%M%S"`
# echo "$ts: begin checking..."
check_process "wx_nanoserver"
[ $? -eq 0 ] && echo "$ts: not running, restarting..." && `php /var/www/wx_nanoserver.php > /var/www/logs/wx_output_$NOW.log 2> /var/www/logs/wx_error_$NOW.log &`
sleep 5
done
try:
pgrep -n -f "$1" && return 1 || return 0
if you use [ ], you will try to check pgrep stdout data, and your script did not compare it with empty space or sth, without [ ], will using pgrep exit code.
Two weird things about your script:
[ `pgrep -n -f $1` ] && return 1 || return 0
works through side effects. The ``` part evaluates to either the pid of the process if found, or nothing if no process is found. The single[notation is a synonym for thetestbuiltin (or command on earlier systems) which happens to returntrueif its argument is a nonempty string andfalseif it is given no argument. So when a pid is found, the test becomes something like[ 1234 ]which evaluates to true and[ ]` otherwise, which evaluates to false. That is indeed what you want, but it would be cleaner to write:
pgrep -n -f "$1" &>/dev/null && return 1 || return 0
Another thing is
`php /var/www/wx_nanoserver.php > /var/www/logs/wx_output_$NOW.log 2> /var/www/logs/wx_error_$NOW.log &`
where you use command substitution for no apparent reason. You're asking bash to evaluate the output of your command rather than simply running it. As its output is redirected, it always evaluates to an empty string so it has no further effect. A side effect is that the command is run in a subshell, which is a good thing to deamonize it. Though, it would be cleaner to write:
( php /var/www/wx_nanoserver.php > /var/www/logs/wx_output_$NOW.log 2> /var/www/logs/wx_error_$NOW.log & )
Not sure though what the actual problem might be. Seems to be working that way anyhow.
Final note, the back tick `` notation has been deprecated in favour of the$()` notation.
I'm trying to customize my bash prompt. I want it so change color if I enter a command that doesn't exist, or for some other reason fails. I'm fairly new with coding bash scripts, so I looked at some other scripts so get some help, but something's not working. Here's my code:
export PROMPT_COMMAND="
PS1='`
if [ $? -eq 0 ];
then echo '
\[\033[00;32m\]┌─\[\033[00;35m\]\u\[\033[01;32m\]#
\[\033[00;35m\]\h\n\[\033[00;32m\]└─\[\033[01;32m\]
(\[\033[01;35m\]\W\[\033[01;32m\])\[\033[00;32m\]\$';
else echo '
\[\033[00;31m\]┌─\[\033[00;35m\]\u\[\033[01;31m\]#
\[\033[00;35m\]\h\n\[\033[00;31m\]└─\[\033[01;31m\]
(\[\033[35m\]\W\[\033[31m\])\[\033[00;31m\]\$';
fi`\[\033[0m\]'"
I do not have any linebreaks in the actual code, since that would be messy with PS1, I just added them to make the code easier to read.
So, I want to compare the exit status, $?, to 0. For some reason the variable $? doesn't change at all in the script. It just remains 0, so the first condition is always true, even when I issue a faulty command. I've tried adding echo $? to the code before the if-case, and this always returns 0, even if issuing echo $? as a command to the terminal returns something different. I've tried copying working code into mine, but that doesn't solve it either. Also, it worked when I used ' as the outer citation and " as the second. I changed this because the script wouldn't accept ( as a character otherwise.
Any ideas why this is and how I can fix it?
The problem in your code is that that your quotation is broken:
export PROMPT_COMMAND="
PS1='`
if [ $? -eq 0 ];
then echo '
Generally it should work, try this:
PS1='`if [ $? -eq 0 ] ; then echo Y:; else echo N:; fi`
Here is the output after applying the code:
$ PS1='`if [ $? -eq 0 ] ; then echo Y:; else echo N:; fi`'
Y:
Y:
Y:
Y:false
N:
N:
N:true
Y:
Y:
Note: Simply pressing the ENTER key, doesn't change the prompt.
Just as as a follow up to H.-Dirk Schmitt's great answer, this works for me (I'm not going to bother explaining the code, that has been done already better than I could);
PS1='`
if [ $? -eq 0 ];
then echo -n "\[\033\[00;35m\]\u\[\033\[01;32m\]#\[\033\[00;35m\]\h\[\033\[00;32m\](\[\033\[01;35m\]\W\[\033\[01;32m\])\[\033\[00;32m\]\$";
else echo -n "\[\033\[00;35m\]\u\[\033\[01;31m\]#\[\033\[00;35m\]\h\[\033\[01;31m\](\[\033\[35m\]\W\[\033\[31m\])\[\033\[00;31m\]\$";
fi`\[\033\[0m\]'
I am using set -e to abort on errors.
But for particular one function I want to ignore error and on error I want return code of the function.
Example:
do_work || true
if [ $? -ne 0 ]
then
echo "Error"
fi
But it is not work return code is always true due || true
How to get return code on do_work on error ?
do_work || {
status=$?
echo "Error"
}
Several of the answers given here are not correct, because they result in a test against a variable that will be un-defined if do_work succeeds.
We need to cover the successful case as well, so the answer is:
set -eu
do_work && status=0 || status=1
The poster's question is a little ambiguous because it says in the text "on error I want return code" but then the code implies "I always want the return code"
To illustrate, here is problematic code:
set -e
do_work() {
return 0
}
status=123
do_work || status=$?
echo $status
In this code the value printed is 123, and not 0 as we might hope for.
You could use a subshell shortcut:
( set +e; do_work )
if [ $? -ne 0 ]
then
echo "Error"
fi
Hope this helps =)
One way is to use a pipe, -e only looks at the right-most result of a pipe:
set -e
do_work | true
retn=${PIPESTATUS[0]}
if (( $retn != 0 ))
then
echo "Error $retn"
fi
echo Ending
I wrote a simple do_work which just did exit 42 and got the following output:
Error 42
Ending
The PIPESTATUS array is maintained by Bash, with each element giving the return code of each part of the pipeline. We need to capture it at once (hence $retn) since it is overwritten at each command.
Of course this might be problematic if your do_work includes a pipe itself.
do_work || status=$?
if [ $status -ne 0 ]
then
echo "Oh no - Fail whale $status has arrived"
fi
In bash script
if [ 1 ]
then
echo "Yes"
else
echo "No"
fi
Output: Yes
It represents that '1' is treated as true value.
But in code:
word = Linux
letter = nuxi
if echo "$word" | grep -q "$letter"
then
echo "Yes"
else
echo "No"
fi
Output: No
But echo "$word" | grep -q "$letter" will return 1, so why is the result is No.
How does the keyword if test the value returned by the command after if?
The return value of a command is checked. [ 1 ] has a return value of 0 (true). Any other return value (like 1) indicates an error.
You can display the return value of the last executed command using the $? variable:
true
echo $?
# returned 0
false
echo $?
# returned 1
echo $?
# returned 0 as the last executed command is 'echo', and not 'false'
In unix land, 0 is true and 1 is false.
For your first example:
if [ 1 ]
then
echo "Yes"
else
echo "No"
fi
"If" checks the exit code of the given command for true/false (i.e. zero/non-zero).
The square brackets actually invoke the "test" command (see "man test" for more information) and give the exit code to if.
"test 1" (or indeed "test any_string") returns true (0) so "Yes" is output.
For your second example, this outputs "No" because "nuxi" isn't found in "Linux", if you change "nuxi" to "nux" (perhaps this was a typo?) and remove the spaces around the = then you will get the behaviour you expect. e.g.
word=Linux
letter=nux
if echo "$word" | grep -q "$letter"
then
echo "Yes"
else
echo "No"
fi
This is because the grep failed to find the $letter in $word, hence the exit code is 1. Whenever a process in linux return a code other than 0 then it means it failed. 0 means exited successfully. You can verify this by echo "Linux" | grep -d "nuxi"; echo $?
On the other hand in scripting world 0 means false and 1 mean true. So the grep failed to find the word and send 1 as an exit code to if, which took it as a true value.