How to use if inside a command in bash script? - bash

I am writing a script in bash, and I have a problem with it:
select opt in "${options[#]}"
do
case $opt in
"1) Check Cassandra Status.")
ssh skyusr#"$IP" "export JAVA_HOME=/opt/mesosphere && /var/lib/mesos/slave/slaves/*/frameworks/*/executors/*/runs/latest/apache-cassandra-3.0.10/bin/nodetool -p 7199 status" | sed -n '6,10p' | awk '{print $1,$2}' | DN="$(grep DN)" | [[if [[!DN]]; echo "All Good" else "Node(s) "$DN" is Down" ;fi]]
;;
"2) Run Repair on all nodes.")
echo "you chose choice 2"
;;
"3) Run Refresh on specific keyspace/Table.")
echo "you chose choice 3"
;;
"4) Optional")
echo "This option disabled"
;;
"Quit")
break
;;
*) echo invalid option;;
esac
done
It gives me
error:line 16: [[if: command not found
All was working until I added this if command, I need to echo a message if $DN is empty else echo another message .

You seem to be confused about some of Bash's basic concepts like pipelines (|) versus compound commands (if and [[). For example awk '{print $1,$2}' | DN="$(grep DN)" does probably not do what you expect:
$ echo $'a\nb'
a
b
$ echo $'a\nb' | B=$(grep a)
$ echo $B
Note how the variable B is not set to "a".
Furthermore your syntax DN="$(grep DN)" | [[if [[!DN]]; echo "All Good" is complete nonsense. You best start by reading some introduction. Then you can continue along the lines of:
A=$(....)
[[ -z $A ]] && echo "A is empty"
# or
if [[ -z $A ]] then echo "A is empty"; else echo "A is not empty"; fi

Change your if condition like below. Your if condition syntax is not correct and then part is also missing. I have just corrected the if condition rest you need to check again.
if [[ DN == "" ]]; then echo "All Good" else echo "Node(s) $DN is Down" ; fi

Related

busybox shell error: line 9 (left square bracket): not found

I have the following code and I get the Error "line 9: [: not found":
#!/bin/sh
msg=$(dmesg | tail -n1)
echo "$msg"
if [ "$msg" = "Tasklet grp12" ]
then
echo "Test was successful, Strings are equal."
else
echo "Test failed, Strings are not equal."
fi
thanks to Charles Duffy! I had to check the box "Builtin version of 'test'" in the shell section of the make menuconfig menu of busybox, to enable string comparison. Now the code works.
Since I had grep activated I first tried another solution which also worked but has a bad performance for sure:
#!/bin/sh
msg=$(dmesg | tail -n1)
echo "$msg"
tasklet="Tasklet grp12"
if ( echo "$msg" | grep "^$tasklet$" )
then
echo "Test was successful, Strings are equal."
else
echo "Test failed, Strings are not equal."
fi

Setting a variable inside a conditional

Is it possible to set a variable from the output of a command inside of a conditional where the conditional is false if nothing gets assigned to the variable.
If I set the variable to a grep with no return and then test:
test=$(echo hello | grep 'helo')
if [[ ! -z $test ]]; then
echo "is set"
else
echo "not set"
fi
Output: not set (this is expected)
But I'm trying to put it all into one statement like this:
test=
if [[ ! -z test=$(echo hello | grep 'helo') ]]; then
echo "is set"
else
echo "not set"
fi
output: "is set" (expected not set)
grep returns success if there is a match, so you can just do:
if test=$(echo hello | grep 'helo')
then
echo "Match: $test"
else
echo "No match"
fi
If you're running something that doesn't differentiate by exit code, you can assign and check in two statements on the same line:
if var=$(cat) && [[ -n $var ]]
then
echo "You successfully piped in some data."
else
echo "Error or eof without data on stdin."
fi
(or ; instead of && if you want to inspect the result even when the command reports failure)
Bit of a hack, using the shell's parameter expansion alternate value syntax, echo -e and some backspaces:
test=$(echo hello | grep 'helo'); echo -e not${test:+\\b\\b\\bis} set
Which outputs is set or not set depending on what grep finds.

BASH - Get number from a file and use it

I have a test.txt file that looks like this:
flask=1.0.1
control=1.0.1
device=1.0.1
Now, I want to create an if statement that if flask=1.0.1, do something and if flash=1.0.1_hotfix do something else.
I tried with grep -iFq but no luck, I am newbie to bash and also to programming.
Can anyone show me a doc that explains how to do so? It's really simple task.
Thank you all!
With bash and if:
source test.txt
if [[ $flask == 1.0.1 ]]; then
echo "do something"
fi
if [[ $flask == 1.0.1_hotfix ]]; then
echo "do something else"
fi
Or with bash and case:
source test.txt
case $flask in
1.0.1)
echo "do something"
;;
1.0.1_hotfix)
echo "do something else"
;;
esac
Or in a denser presentation:
source test.txt
case $flask in
1.0.1) echo "do something" ;;
1.0.1_hotfix) echo "do something else" ;;
esac
Grep is fine, just notice that flask=1.0.1 is a substring of flask=1.0.1_hotfix, so you need to do full string comparison or check for the string end.
flask=$( grep ^flask= test.txt )
if [ "$flask" == flask=1.0.1 ] ; then
...
elif [ "$flask" == flask=1.0.1_hotfix ] ; then
....
fi
I've understood you correctly?
[root#212-24-57-104 Build]# cat 1
flask=1.0.1
control=1.0.1
device=1.0.1
[root#212-24-57-104 Build]# cat ez.sh
#!/bin/bash
a=( $(cat 1) )
for ver in "${a[#]}"
do
if [ $(echo "${ver}" | awk -F= '{print $NF}') == "1.0.1" ]
then
echo "Do something virh $ver"
else
echo "Do anything else with $ver"
fi
done
A couple of other options:
use grep to get the value
flask_value=$( grep -oP '^flask=\K.*' test.txt )
case $flask_value in
1.0.1) ... ;;
# etc
esac
iterate over the file with just bash:
while IFS="=" read var value; do
if [[ $var == "flask" ]]; then
case $value in
1.0.1) ... ;;
# etc
esac
fi
done < test.txt

email shell script part 2

I'm creating a shell script that takes in user input and text's people using the mail function. I am looking to make it more advanced. Right now it just text's one person at a time, I want it to have the ability to text multiple people or even everyone with a user input of 'All'.
#!/bin/sh
# Prefix the numbers with something
number_Joe=8881235555
number_Bob=8881235556
echo "Who do you want to text?:(i.e. Joe, Bob, etc)"
read name
echo "What do you want to say?:"
read quote
# Remove any dangerous characters that the user enters
sanitized=$(printf "%s" "$name" | tr -cd 'a-zA-Z')
#Look up by evaluating e.g. "number=$number_Joe"
eval "number=\$number_$sanitized"
if [ "$number" ]
then
echo "texting $name ($number) with $quote"
printf "%s\n" "$quote" | mailx -s "Text Message via email" "$number#txt.att.net"
else
echo "Unknown user"
exit 1
fi
Also, is there a cleaner method of bringing in a external txt file that houses the numbers instead of the script?
(note: we still have bash <4, thus why I'm not using a associative array)
Here's a rewrite.
Should work fine in bash3.
#!/bin/bash
# Prefix the numbers with something
names=()
names+=(Joe); numberJoe=8881235555
names+=(Bob); numberBob=8881235556
domain=txt.att.example.com
usage () {
echo "usage: $(basename $0) names message ..."
echo "where: names is a comma-separated list of names (no spaces)"
echo
echo "example: $(basename $0) Jim,Fred hello lads, this is my message"
}
while getopts ":hl" opt; do
case $opt in
h) usage; exit ;;
l) IFS=,; echo "known names: ${names[#]}"; exit ;;
esac
done
shift $((OPTIND - 1))
if (( $# < 2 )); then
usage
exit
fi
IFS=, read -ra usernamelist <<<"$1"
shift
message="$*"
# validate names
namelist=()
for name in "${usernamelist[#]}"; do
if [[ " ${names[#]} " == *" $name "* ]]; then
namelist+=("$name")
else
echo "unknown name: $name" >&2
fi
done
if (( ${#namelist[#]} == 0 )); then
echo "no valid names given" >&2
exit 1
fi
# generate the recipient list
echo "texting '$message' to:"
recipients=()
for name in "${namelist[#]}"; do
numvar="number$name"
echo " $name -> ${!numvar}"
recipients+=( "${!numvar}#$domain" )
done
# send it
printf "%s\n" "$message" | mailx -s "Text Message via email" "$(IFS=,; echo "${recipients[*]}")"

Bash script that detects the type of argument it's given

I have a bash script that will take one argument: a product ID. The product ID can be in one of two formats: all numbers, or a mix of letters, numbers, and underscores. Depending on which type of ID is entered, the script will handle it in a slightly different way.
Right now, I'm using getopts with one flag for each subtype to distinguish between which type of product ID I'm going to be using in the script. For example:
./myscript -n 1034596
or
./myscript -v AB_ABCD_12345
With a simplified version of the script looking like this:
#!/bin/bash
while getopts ":n:v:" opt; do
case $opt in
n)
echo "This is a numbers only ID." >&2
;;
v)
echo "This is a letters, numbers, underscore ID" >&2
;;
esac
done
Since the formats are static, that is, the first type of ID will never be anything but numbers, is there any way to automatically distinguish between the two types of IDs and handle them appropriately without the need for the -n or -v flag? So, I could just enter ./myscript 1034596 and the script will know that since the argument contains nothing but numbers it should process it a specific way.
#!/bin/bash
shopt -s extglob
case "$1" in
+([0-9]) ) echo "This is a numbers only ID." >&2
;;
+([a-zA-Z0-9_]) ) echo "This is a letters, numbers, underscore ID" >&2
;;
*) echo "Unrecognized Product ID" >&2
esac
Pure Bash 3.X
#!/bin/bash
if [[ "$1" =~ ^[0-9]+$ ]]; then
echo "This is a numbers only ID." >&2
else
echo "This is a letters, numbers, underscore ID" >&2
fi
Output
$ ./argtype.sh 1034596
This is a numbers only ID.
$ ./argtype.sh AB_ABCD_12345
This is a letters, numbers, underscore ID
Try this code:
#!/bin/bash
if [ $1 -eq $1 2> /dev/null ]; then
echo number
else
echo not number
fi
The output on your given input is:
brent#battlecruiser:~$ ./test2 1034596
number
brent#battlecruiser:~$ ./test2 AB_ABCD_12345
not number
There is a perhaps slightly more readable way with bash, but this can be done perfectly reasonably in pure portable sh.
unset LC_COLLATE
case $1 in
*[!0-9A-Z_a-z]*) echo 1>&2 "Invalid product ID"; exit 2;;
*[!0-9]*) echo "alphanumeric product ID";;
*) echo "numeric product ID";;
esac
Take a look at accepted the answer to this question. Around line 8 is a regex technique that you can adapt.
#!/bin/sh
arg="$1"
output=`echo "$1" | grep -o "[0-9]\+"`
if [ "$output" == "$arg" ]; then
echo "Numbers only"
else
echo "Mixed"
fi
In Bash 3.2 or greater:
pattern1='^[0-9]+$'
pattern2='^[0-9a-zA-Z_]+$'
if [[ $1 =~ $pattern1 ]]
then
echo "argument consists only of digits and is validated"
else
echo "argument contains other characters"
if [[ $1 =~ $pattern2 ]]
then
echo "argument is validated"
else
echo "argument contains invalid characters"
fi
fi
You could use grep to validate if the string passed in is a number:
#!/bin/bash
echo $1 | grep -q "^[0-9]*$"
if [ $? ]; then
echo "Number"
else
echo "Not a number"
fi
With comments updates:
#!/bin/bash
if grep -q "^[0-9]*$" <<< "$1"; then
echo "Number"
else
echo "Not a number"
fi

Resources