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\]'
Related
I'm trying to implement a bash script who supposed to search for a word in a Python script terminal output.
The Python script doesn't stop so "&" in the end of the command is needed but the "if [ $? == 0 ] ; then" condition doesn't work.
How it can be solved?
Thanks, Gal.
#!/bin/bash
#Check if Pixhawk is connected
PORT=/dev/ttyPixhawk
end=$((SECONDS+3))
not_exists=f
/usr/local/bin/mavproxy.py --daemon --non-interactive --master=$PORT | grep 'Failed' &> /dev/null &
while [ $SECONDS -lt $end ] ; do
if [ $? == 0 ] ; then
not_exists=t
fi
sleep 1
done
if [ $not_exists=t ] ; then
echo "Not Exists"
else
echo "Exists"
fi
kill $(pgrep -f '/usr/local/bin/mavproxy.py')
Bash doesn't know anything about the output of background commands. Check for yourself with [ 5444 -lt 3 ] & echo $?.
your if statement wouldn't work in any case because $? checks for the return value of the most recent previous command, which in this case is your while loop.
You have a few different options. If you're waiting for some output, and you know how long it is in the output until whatever target you're looking for occurs, you can have the python write to a file and keep checking on the file size with a timeout for failure.
You can also continue with a simple timed approach as you have where you just check the output after a few seconds and decide success or failure based on that.
You can make your python script actually end, or provide more error messages, or write only the relevant parts to file that way.
Furthermore, you really should run your script through shellcheck.net to notice more problems.
You'll need to define your goal and use case more clearly to get real help; all we can really say is "your approach will not work, but there are definitely approaches which will work"
You are checking the status of grep command output inside while loop using $?. This can be done if $? is the next command to be fired after grep and if grep is not a back-group process . But in your script, $? will return the status of while [$SECONDS -lt $end ]. You can try to re-direct the output to a temp file and check it's status
/usr/local/bin/mavproxy.py --daemon --non-interactive --master=$PORT | grep 'Failed' &> tmp.txt &
sleep 3
# If file exists and it's size is greater than 0, [ -s File] will return true
if [ -s tmp.txt ]; then
echo 'pattern exists'
else
echo 'pattern not exists'
fi
So I have this If statement that checks what the exit code of the script is:
if [ $? -eq 0 ]; then
wasSuccessful=true;
fi
In other languages, I would do something like:
while wasSuccessful == false
And then the loop would keep running until the exit code was true. (I plan to implement a loop counter as well for too many failed attempts, but that's a different problem to solve)
I think I need a here-string, but I'm not exactly sure how that would look. Here's a rough outline of my code right now, in Bash:
wasSuccessful=false
while [ "$wasSuccessful" = "false" ]
do
#Bunch of code here, then the check for exit code
if [ $? -eq 0 ]; then
wasSuccessful=true;
fi
done
Any suggestions on how to do something like this would be much appreciated :)
The question is how to exit while loop when the latest command execute successfully inside while loop?
You don't need a global variable to check. Just check the status of previous command and break it if succeed.
while true
do
# a bunch of code here
[ $? -eq 0 ] && break
done
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
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 know I already had this running quite some time ago, but I haven't messed around with scripts and bash prompts for a long time an I am unable to come up with a solution.
I tried to use if [ $? = 0 ]; then; else;, in order to become a different prompt if a command provides an error and \$, in order to get a #, in case root is logged in. I even came up with this nonsensical long prompt command:
PROMPT_COMMAND='if [ $? = 0 ]; then PS1="\[\e[31m\]║\[\033[04;35m\]\$(/bin/date)\[\e[00;32m\] History: \! \[\e[31m\]Jobs: \j \[\e[34m\]Status: \[\e[32m\]▇▇ ${debian_chroot:+($debian_chroot)}\n\[\033[31m\]║\[\e[33m\]\u#\[\e[37m\]\w/\[\e[32m\]\$:\[\e[0m\]"; else PS1="\[\e[31m\]║\[\033[04;35m\]\$(/bin/date)\[\e[00;32m\] History: \! \[\e[31m\]Jobs: \j \[\e[34m\]Status: \[\e[31m\]▇▇ ${debian_chroot:+($debian_chroot)}\n\[\e[31m\]║\[\e[33m\]\u#\[\e[37m\]\w/\[\e[32m\]\$:\[\e[0m\]"; fi'
I know the problem is that the if [ $? = 0 ]; then; else; portion works between "", while the /$ seems to work only between ''.
The funny thing is that this works ...
PS1="\`if [ \$? = 0 ]; then echo \[\e[33m\]^_^\[\e[0m\]; else echo \[\e[31m\]O_O\[\e[0m\]; fi\`[\u#\h:\w]\\$ "
while this doesn't (the if [ \$? = 0 ]; then; else;) (\$(/bin/date) and \$ works this way)
PS1="\[\033[31m\]║\[\033[04;35m\]\$(/bin/date)\[\033[00;32m\] History: \! \[\033[31m\]Jobs: \j \`if [ \$? = 0 ]; then echo \[\e[34m\]Status: \[\e[32m\]▇▇; else echo \[\e[34m\]Status: \[\e[31m\]▇▇; fi\` ${debian_chroot:+($debian_chroot)}\n\[\033[31m\]║\[\033[33m\]\u#\[\033[37m\]\w/\[\033[32m\]\\$:\[\033[0m\]"
I'd like to keep both in my prompt, but I am obviously missing something (maybe because I was looking at this prompt too much. I would be glad to have a prompt that features \$ and \$(/bin/date), while changing if an error occurs, please help.
Cheers.
I recommend building your prompt from PROMPT_COMMAND, rather than trying to cram executable code into the value of PS1 itself. This makes the quoting simpler, as well as breaking the prompt into manageable pieces.
prompt_cmd () {
exit_status=$?
PS1='\[\e[31m\]║\[\e[04;35m\]\D{%+}'
PS1+=' \[\e[32m\]History: \!'
PS1+=' \[\e[31m\]Jobs: \j'
PS1+=' \[\e[34m\]Status: '
if [[ $exit_status = 0 ]]; then
PS1+='\[\e[32m\]'
else
PS1+='\[\e[31m\]'
fi
PS1+='▇▇ '"${debian_chroot:+($debian_chroot)}"'\n'
PS1+='\[\e[31m\]║\[\e[33m\]\u#\[\e[37m\]\w\[\e[32m\]\$:\[\e[0m\]'
}
PROMPT_COMMAND='prompt_cmd'