bash script if elif statement - bash

keep getting this error when I run the script, not sure what went wrong, this is if elif with or condition statement
line xx: ((: WEST - Very Big=EAST - BIG: syntax error in expression (error token is "WEST - Very Big")
echo "$yn"
if (($yn=EAST - BIG)) || (($yn=EAST - SMALL))
then
echo "---------------------------------------------------------------------------" >> /tmp/"$HOSTNAME".log
elif (($yn=WEST - Very Big)) || (($yn=WEST - Very Small))
then
echo "---------------------------------------------------------------------------" >> /tmp/"$HOSTNAME".log
else
echo "---------------------------------------------------------------------------" >> /tmp/"$HOSTNAME".log
fi

Several issues. The check for equality inside (( )) is == (a single = is an assignment). This is common to many languages.
You are not allowed whitespace inside a variable name (assuming those are variable names). The characters allowed in a variable name are ASCII alphanumerics or an underscore, and the first character cannot be a number.
It is also a bad idea to use all UPPERCASE for your own variable names. The shell sets and uses a large number of UPPERCASE variables itself, and you could stomp on each other's values.
Here is my test version of your code:
yn=42
EAST=52
BIG=100
WEST=45
Very_Big=3
Very_Small=1
HOSTNAME='fred'
# Here I used a variable to avoid repeating myself
# that makes it easier to change the filename later
outfile="/tmp/$HOSTNAME.log"
> "$outfile" # Zero the file
echo "$yn"
if (($yn == EAST - BIG )) || (($yn == EAST - SMALL ))
then
echo "---------------------------------------------------------------------------" >> "$outfile"
elif (($yn == WEST - Very_Big )) || (($yn == WEST - Very_Small))
then
echo "---------------------------------------------------------------------------" >> "$outfile"
else
echo "---------------------------------------------------------------------------" >> "$outfile"
fi
Code is much easier to read when you use consistent indentation. To trace how a bash program is running, use -x, for example:
bash -x myscript

Related

Bash script to beep when temperature hot on FreeBSD

I have been working on a Bash script to beep when the PC is too hot.
I have removed the beep to try identifying the problem.
What I have so far:
temp=$(sysctl -n hw.acpi.thermal.tz0.temperature | tr -d 'C')
echo $temp
if ["$temp" -gt "30.1"]
then
echo "temp hot"
else
echo "temp ok"
fi
My output is
54.1
temp.sh: line 4: [54.1: command not found
temp ok
Removing the if statement just outputs
54.1
so I think it's the if statement that's not working.
You should use double parenthesis (( )) to do arithmetic expressions, and since Bash cannot handle decimal values, you just have to remove the dot (as if you want to multiply it by ten).
temp=$(sysctl -n hw.acpi.thermal.tz0.temperature | tr -d 'C')
max_temp=50.2
(( ${temp//./} > ${max_temp//./} )) && echo "temp hot" || echo "temp ok"
Be sure to use the same format for both values (especially leading zeros, 54.10 would become 5410).
If the format cannot be guaranteed, there is a second method, as mentioned by Benjamin W, using bc. You can send to this command a logical operation involving floats, it returns 0 if true, 1 otherwise.
temp=$(sysctl -n hw.acpi.thermal.tz0.temperature | tr -d 'C')
max_temp=50.2
(( $(echo "$temp > $max_temp" | bc) )) && echo "temp hot" || echo "temp ok"
Your immediate problem is syntax error -- you omitted the space between the command ([ -- /bin/[) and its arguments ($temp). The last argument of [ must be ] -- your script is missing a blank there too, which makes the last argument "30.1"]. The quotes aren't necessary here, BTW, and only make things harder to read.
This is a generic sh-scripting quation, it has nothing to do with FreeBSD nor with temperature-measuring.

Trying to escape the backslash in this bash script

The following bash script takes any input of numbers between 0-100 and prints out an average of the numbers to the screen. The script also has input validation that won't allow anything but a number between 0-100 and a q or Q. Once you enter a q or Q it computes the results and outputs to the screen. Input validation also checks to make sure there are no null values entered, special characters entered and that there are no number/letter combinations, special character/number combinations etc. entered.
The only problem I have is with the backslash character. The backslash is escaped in this script and when I run the script and enter a backslash it pauses and requires you to press return for the script to continue. Seems like the script still works but I'm curious about why it pauses. Most of the recommendations I've seen on this on this site have been to escape the backslash with more backslashes but that doesn't work.
#! /bin/bash
AVERAGE="0"
SUM="0"
NUM="0"
clear
while true; do
echo -n "Enter your score [0-100%] ('q' for quit): "; read SCORE;
if [[ "$SCORE" == *[a-pA-pr-zR-Z]* ]] ||
[[ "$SCORE" == *['!'\\##\$%^\&*()_+~\`\-=\[\]\{\}\|:\;\'\"\<\>,.?/\\]* ]] ||
[[ -z "$SCORE" ]] ||
(( "$SCORE" < "0" )) || (( "$SCORE" > "100" ))
then
echo "Be serious. Come on, try again: "
elif [[ "$SCORE" == [qQ] ]]; then
echo "Average rating: $AVERAGE%."
break
else
SUM=$[$SUM + $SCORE]
NUM=$[$NUM + 1]
AVERAGE=$[$SUM / $NUM]
fi
done
echo "Exiting."
Use read -r to disable backslash escaping, which is enabled by default.
Options:
-r do not allow backslashes to escape any characters

Double-bracket if-statement not working

if [[ $nb_dd > 0 ]]; then
INPUT_TYPE="txt"
fi
if [ $nb_dd > 0 ]; then
INPUT_TYPE="txt"
fi
The first check (using double brackets) fails to execute, causing the script to exit upon error as $INPUT_TYPE is not populated - but the latter version (single bracket) works, correctly setting $INPUT_TYPE. Why is this?
I'm running on OS X (10.11.4) (echo $SHELL = /bin/bash) - this is from a widely distributed suite of tools which were presumingly built on a Linux platform - and the .sh script otherwise works for the author so it may be a platform-specific issue although I can't think why.
They both "work" for me, however you are using the wrong type of test. The > inside [[ is doing a textual comparison. For an arithmetic comparison either use the old -gt or (better) the correct brackets - double parentheses:
if (( nb_dd > 0 )); then
INPUT_TYPE="txt"
fi
Note that the $ is not used, since only numerics can be compared inside ((...)) (using a $ inside might work but can give strange side-effects because of expansion order).
You must gt and lt to make comparisons,
if [[ $nb_dd -gt 0 ]];
then INPUT_TYPE="txt";
fi
if [ $nb_dd -gt 0 ];
then INPUT_TYPE="txt";
fi
Double brackets just extend posix functionality
> means nothing in posix compliant test expressions, and it just calls the output redirection.
[ 2 > 3 ] && echo "shouldn't print this"
[ 2 -gt 3 ] && echo "this isn't printed"
On extensions expressions to the posix ones it means sting comparison.
[[ "aa" > "ab" ]] && echo "doesn't print"
[[ "aa" > "aa" ]] && echo "doesn't print"
[[ "ab" > "aa" ]] && echo "prints"

reading the first line from each file and comparing them to a reference number

I have three input files. I will read the first line of each the input file and I will compare them to a reference number. All values (a1,a2 and a3) I read from different input files should smaller than my "absolute reference value (aref)". My script gives the error for the reference value: line ..: -2.13: No such file or directory. How can I fix my code? And my if condition is correct?
#!/bin/bash -f
a1=$(head -n 1 input1.xvg)
a2=$(head -n 1 input2.xvg)
a3=$(head -n 1 input3.xvg)
aref=-2.13
if [a1 < $aref && a2 < $aref && a3 < $aref] ; then
echo "It's good"
else
echo "It isn't good"
fi
As well as your syntax errors (you need spaces after [ and before ] in a test and you're missing some $ from your variable names), it looks like you're trying to compare floating point numbers, which is not supported by bash. One option would be to use bc, inside an arithmetic context instead:
if (( $(bc <<<"$a1 < $aref && $a2 > $aref && $a3 > $aref") )); then
echo "It's good"
else
echo "It isn't good"
fi
The output of the command substitution $( ... ), is 1 or 0, depending on whether the conditions are true or false. The arithmetic context (( ... )) returns success if the output is returns 1 and failure if it returns 0.
If you would like to work with the absolute values of your variables, one way to do so would be to use ${a1#-}, ${aref#-}, etc. which removes the leading - from each variable.
Use [[ instead of [ in your if statement. Because you're using [ the shell thinks you are passing a file, not comparing to values.
Try to write your if like this
if [[ $a1 < $aref && $a2 > $aref && $a3 > $aref ]] ; then
To use the absolute value of aref use this:
let "aref=$aref<0?-$aref:$aref"

Simplifying advanced Bash prompt variable (PS1) code

So I've found the following cool Bash prompt:
..with the very basic logic of:
PS1="\[\033[01;37m\]\$? \$(if [[ \$? == 0 ]]; then echo \"\[\033[01;32m\]\342\234\223\"; else echo \"\[\033[01;31m\]\342\234\227\"; fi) $(if [[ ${EUID} == 0 ]]; then echo '\[\033[01;31m\]\h'; else echo '\[\033[01;32m\]\u#\h'; fi)\[\033[01;34m\] \w \$\[\033[00m\] "
However, this is not very basic and happens to be an incredible mess. I'd like to make it more readable.
How?
Use PROMPT_COMMAND to build the value up in a sane fashion. This saves a lot of quoting and makes the text much more readable. Note that you can use \e instead of \033 to represent the escape character inside a prompt.
set_prompt () {
local last_command=$? # Must come first!
PS1=""
# Add a bright white exit status for the last command
PS1+='\[\e[01;37m\]$? '
# If it was successful, print a green check mark. Otherwise, print
# a red X.
if [[ $last_command == 0 ]]; then
PS1+='\[\e[01;32m\]\342\234\223 '
else
PS1+='\[\e[01;31m\]\342\234\227 '
fi
# If root, just print the host in red. Otherwise, print the current user
# and host in green.
# in
if [[ $EUID == 0 ]]; then
PS1+='\[\e[01;31m\]\h '
else
PS1+='\[\e[01;32m\]\u#\h '
fi
# Print the working directory and prompt marker in blue, and reset
# the text color to the default.
PS1+='\[\e[01;34m\] \w \$\[\e[00m\] '
}
PROMPT_COMMAND='set_prompt'
You can define variables for the more esoteric escape sequences, at the cost of needing some extra escapes inside the double quotes, to accommodate parameter expansion.
set_prompt () {
local last_command=$? # Must come first!
PS1=""
local blue='\[\e[01;34m\]'
local white='\[\e[01;37m\]'
local red='\[\e[01;31m\]'
local green='\[\e[01;32m\]'
local reset='\[\e[00m\]'
local fancyX='\342\234\227'
local checkmark='\342\234\223'
PS1+="$white\$? "
if [[ $last_command == 0 ]]; then
PS1+="$green$checkmark "
else
PS1+="$red$fancyX "
fi
if [[ $EUID == 0 ]]; then
PS1+="$red\\h "
else
PS1+="$green\\u#\\h "
fi
PS1+="$blue\\w \\\$$reset "
}

Resources