Rebuild shell script to case - linux

I want to rebuild my script a little bit to make it more easier for other people.
I think it will be more easier with case and functions.
IP="192.168.123." #$1 is the last number for the ip-address
regExp="^[0-9]+[-,0-9]*$"
if [ "$#" -eq 0 ]; then
echo "No numbers given "
exit 0
fi
if [ "$1" == "-h" ]; then
echo "Give numbers to test"
exit 0
fi
I want to make something like this:
if [ "$#" -eq 0 ]; then
echo "No numbers given "
# exit 0 --> do I have to write this?
case
-h ) echo "Give numbers to test";
esac
fi
Do I have to write that exit?
Are there things to make it easier?

If all your statements are inside the case then you don't need the exit
case "$1" in
'') echo No numbers given;;
-h) echo Give numbers to test;;
*) ...
esac

Related

Bash IF/ELIF statements

So I am learning bash and wanted to make a script to 'automate' a collection of kali tools. Basically I do not understand why the if statement code is being triggered regardless if condition is true or false.
#!/bin/bash
#requires root or sudo priv
#check for a successful ping
target_ip=$1
nmap_opt = " "
#nmap options variables --
nmap_os="-O"
nmap_version="-sV"
nmap_udp="-sU"
nmap_stealth="-sS"
nmap_aggr="-A"
nmap_option_input_temp=""
ping $target_ip -c 5
if [ $? -eq 0 ]; then
echo "successful ping on" $target_ip
else
echo "ping unsuccessful, check VPN connection or host may be down"
exit 1
fi
read -p "enter pathway for nmap output: " nmap_file
read -p "detect os? (y/n) " nmap_option_input_temp
#add loops for y/n user input
if [[ ${nmap_option_input_temp} -eq "y" ]];
then
nmap_opt="${nmap_opt} ${nmap_os}"
elif [[ ${nmap_option_input_temp} -eq "n" ]];
then
nmap_opt=$nmap_opt
else
echo "invalid option"
fi
read -p "detect version? (y/n) " nmap_option_input_temp
#add loops for y/n user input
if [[ ${nmap_option_input_temp} -eq "y" ]];
then
nmap_opt="${nmap_opt} ${nmap_version}"
elif [[ ${nmap_option_input_temp} -eq "n" ]];
then
nmap_opt=$nmap_opt
else
echo "invalid option"
fi
echo "nmap selected option/s:" $nmap_opt
echo $nmap_option_input_temp
#starting nmap..
sudo nmap $nmap_opt -oN $nmap_file $target_ip
this is the nmap_opt variable echo out even when both inputs are 'n'
nmap selected option/s: -O -sV
Let me know if there is anything I missed in the explanation!
-eq is for integer comparisons. Use ==:
if [[ "${nmap_option_input_temp}" == y ]];
And fix your quotes. Fixed strings like y don't need to be quoted. Inside [[, variables don't need to be quoted, but IMO you should quote them anyway for consistency.
This error would be more easily spotted if you used the more conventional:
if [ "${nmap_option_input_temp}" -eq y ]; # Still incorrect!!
since you would get a nice error message.
Note that the fix with [ is slightly different, and you should use a single =:
if [ "${nmap_option_input_temp}" = y ];
The == operator is a bashism which does not really add any value. But really, you should not be using if/elif at all here. This is the perfect place for a case statement:
case "${nmap_option_input_temp}" in
y) nmap_opt="${nmap_opt} ${nmap_os}";;
n) ;;
*) echo "invalid option" >&2 ;;
esac

Read string and convert to INT (BASH)

I have a simple script in Bash to read a number in a file and then compare it with a different threshold. The output is this:
: integer expression expected
: integer expression expected
OK: 3
My code is this:
#!/bin/bash
wget=$(wget http://10.228.28.8/ -O /tmp/wget.txt 2>/dev/null)
output=$(cat /tmp/wget.txt | awk 'NR==6')
#output=7
echo $output
if [ $output -ge 11 ];then
echo "CRITICAL: $output"
exit 2
elif [ $output -ge 6 ] && [ $output -lt 11 ];then
echo "WARNING: $output"
exit 1
else
echo "OK: $output"
exit 0
fi
rm /tmp/wget.txt
I know what is the problem, I know that I'm reading a string and I try to compare a int. But I don't know how can I do to read this file and convert the number to read in a int var..
Any ideas?
The problem occurs when $output is the empty string; whether or not you quote the expansion (and you should), you'll get the integer expression required error. You need to handle the empty string explictly, with a default value of zero (or whatever default makes sense).
wget=$(wget http://10.228.28.8/ -O /tmp/wget.txt 2>/dev/null)
output=$(awk 'NR==6' < /tmp/get.txt)
output=${output:-0}
if [ "$output" -ge 11 ];then
echo "CRITICAL: $output"
exit 2
elif [ "$output" -ge 6 ];then
echo "WARNING: $output"
exit 1
else
echo "OK: $output"
exit 0
fi
(If you reach the elif, you already know the value of $output is less than 11; there's no need to check again.)
The problem also occurs, and is consistent with the error message, if output ends with a carriage return. You can remove that with
output=${output%$'\r'}
There are a couple of suggestions from my side regarding your code.
You could explicitly tell bash the output is an integer
declare -i output # See [1]
Change
output=$(cat /tmp/wget.txt | awk 'NR==6') # See [2]
may be better written as
output=$(awk 'NR==6' /tmp/wget.txt )
Change
if [ $output -ge 11 ]
to
if [ "0$output" -ge 11 ] # See [4]
or
if (( output >= 11 )) # Better See [3]
References
Check bash [ declare ].
Useless use of cat. Check [ this ]
Quoting [ this ] answer :
((...)) enable you to omit the dollar signs on integer and array variables and include spaces around operators for readability. Also empty variable automatically defaults to 0 in such a statement.
The zero in the beginning of "0$output" help you deal with empty $output
Interesting
Useless use of cat is a phrase that has been resounding in SO for long. Check [ this ]
[ #chepner ] has dealt with the empty output fiasco using [ bash parameter expansion ] in his [ answer ], worth having a look at.
A simplified script:
#!/bin/bash
wget=$(wget http://10.228.28.8/ -O /tmp/wget.txt 2>/dev/null)
output=$(awk 'NR==6' </tmp/wget.txt )
output="$(( 10#${output//[^0-9]} + 0 ))"
(( output >= 11 )) && { echo "CRITICAL: $output"; exit 2; }
(( output >= 6 )) && { echo "WARNING: $output"; exit 1; }
echo "OK: $output"
The key line to cleanup any input is:
output="$(( 10#${output//[^0-9]} + 0 ))"
${output//[^0-9]} Will leave only digits from 0 to 9 (will remove all non-numeric chars).
10#${output//[^0-9]} Will convert output to a base 10 number.
That will correctly convert numbers like 0019
"$(( 10#${output//[^0-9]} + 0 ))" Will produce a zero for a missing value.
Then the resulting number stored in output will be compared to limits and the corresponding output will be printed.
In BASH, It is a good idea to use double brackets for strings:
if [[ testing strings ]]; then
<whatever>
else
<whatever>
fi
Or double parenthesis for integers:
if (( testing ints )); then
<whatever>
else
<whatever>
fi
For example try this:
var1="foo bar"
if [ $var1 == 'foo bar' ]; then
echo "ok"
fi
Result:
$ bash: [: too many arguments
Now, this:
var2="foo bar"
if [[ $a == "foo bar" ]]; then
echo "ok"
fi
Result:
ok
For that, your code in BASH:
if [[ $output -ge 11 ]]; then
echo "CRITICAL: $output"
exit 2
elif [[ $output -ge 6 ]]; then
echo "WARNING: $output"
exit 1
else
echo "OK: $output"
exit 0
fi

nitrogen --restore to scale background

so I found a script online and found it pretty suitable to my needs. basically it edits the file nitrogen places it's saved wallpaper in to another picture, so I can change the wallpaper periodically with a cron job.
#!/bin/bash
WPDIR="$HOME/Wallpapers"
random=true
apply=true
wpfile=""
function usage {
if [ $1 -eq 1 ]; then
stream=2
exitcode=255
else
stream=1
exitcode=0
fi
echo "Usage: $(basename $0) [-n|--noapply] [-h|--help] [wallpaper_location]" >&$stream
echo "If wallpaper location is not given a random wallpaper from $WPDIR will be chosen" >&$stream
exit $exitcode
}
# handle arguments
while [ $# -gt 0 ]; do
if [ "$1" = "--help" -o "$1" == "-h" ]; then
usage 0
elif [ "$1" = "--noapply" -o "$1" = "-n" ]; then
apply=false
else
if ! $random; then
usage 1
elif [ ! -f "$1" ]; then
echo "file '$1' not found" >&2
exit 1
fi
random=false
{ cd $(dirname "$1"); dir=$(pwd); }
wpfile="$dir/$(basename "$1")"
fi
shift
done
if $random; then
wpfile=$(ls "$WPDIR"/*.jpg | sort -R | head -n 1)
echo "chose $wpfile" >&2
fi
cat >$HOME/.config/nitrogen/bg-saved.cfg <<EOF
[:0.0]
file=$wpfile
mode=4
bgcolor=# 0 0 0
EOF
if $apply; then
nitrogen --restore
fi
my problem is the scaling of the pictures. I can't set it to auto-fill this way.
I'm bad, I should feel bad. When writing to >$HOME/.config/nitrogen/bg-saved.cfg , the mode is set. this mode is literally the mode nitrogen provides. Try a bit around with nitrogen and look what mode is set in the file. zoomed-fill = 5, for my example.

Script with parameter

I supossed to make a script that given an number it count to 0, I managed to do this and it's working:
#!/bin/bash
echo -n "type a number: "
read number; echo
while [ $number -ge 0 ]; do
echo -n "$number"
number=$((number-1))
done
echo
Well, I changed it because I need to pass the number by an parameter ex: "./script 5" and it must show the countdown till 0, but its getting in looping. I kind new on all it script/stack what Im doing wrong?
#!/bin/bash
if [ "$*" = "" ]; then
echo
echo "not correct"
echo "must be a int number"
echo
exit
fi
while [ "$1" -ge 0 ]; do
echo "$1"
cont='expr $1-1'
done
echo
You're always using [ "$1" -ge 0 ] as your condition, but the value you actually modify/update is cont, not $1. (Moreover, you modify it based on the value of $1, which isn't changing, so you only ever set $cont to one less than the original value of $1).
Consider:
#!/bin/bash
[[ $1 ]] || { printf '%s\n' "First argument must be an integer" >&2; exit 1; }
for ((i=$1; i>=0; i--)); do
echo "$i"
done
...and note, among the various changes:
We're consistently referring to the first argument passed as $1, rather than also sometimes referring to it as $*
When we select a variable to modify ($i, here, rather than $cont), we use that same variable in our tests, and also as the source for modification in the loop.
Using expr for math is antiquated; POSIX sh allows $(( )) to create a math context, and bash extends this to also allow C-style for loops in a math context.

Detect number of argument and the value passed into the bash

I want to make sure my bash script can correctly detect user's input argument. Specifically, user can only pass 1 or 2 or 3 into the script, otherwise the script will be terminated. I wrote the following code:
#!/bin/bash
for args in $#
do
echo $args
done
if [ "$#" != 1 ] && [ "$#" -ne 1 ]; then
echo "Illegal number of parameters"
exit 1
fi
This script can only capture when user does not give any input, but cannot check whether user indeed input the number 1 not other values.
By the way, I am not sure how to express "input argument can accept number 1 or 2 or 3".
$# is an integer, so you have to use integer comparison. You can for example say:
if [ "$#" -ne 1 ]; then
echo "illegal number of parameters"
exit 1
fi
To check that the parameter is either 1, 2 or 3, you can use this regular expression (see something related):
if [[ ! $1 =~ ^(1|2|3)$ ]]; then
echo "the number is not 1, 2 or 3"
exit 1
fi
To express "input argument can accept number 1 or 2 or 3" I would for example say "we can just accept the argument being either 1, 2 or 3".
First off you can detect if the string is null or empty simply by doing the following:
if [ -z "$1" ]
then
echo "Argument $1 contains nothing"
fi
That I would say is your first step, and will allow you to filter out args that have no content.
Following on from that, you'd most likely need to do some comparison work on $1, $2 & $3
I'll just check something and come back to this in a moment.
Update
Just had to go find one of my scripts and check something... :-)
One way I've handled the checking of parms in the past is something like the following
#!/bin/sh
while [ $# -gt 0 ] || [ "$#" -le 4 ]; do
case "$1" in
*[!1-9]*) echo "Text: $1";;
*) echo "Number: $1"
esac
case "$2" in
*[!1-9]*) echo "Text: $2";;
*) echo "Number: $2"
esac
case "$3" in
*[!1-9]*) echo "Text: $3";;
*) echo "Number: $3"
esac
shift
done
Basically a simple regex, if I have more than 0 parameters or less than 4 parameters then I allow it through to a case statement, which then checks the content of each parameter.
This one just has an echo in, but you could just as easy set some flags, and then decide how to continue based on those flags.
For simple range checking however, you might just want to use a one liner similar to the following:
if [[ $# -gt 0 && $# -lt 4 ]]; then echo "Correct number of parameters"; fi
Again setting a flag to use later rather than echoing the results.
I assume you mean the input can only be 1, 2 or 3, so using a case statement is the best way. $1 is the variable that stores your argument, if it is equal to 1 case will execute the code in the block corresponding to the value 1 and so on.
case "$1" in
1) ...
;;
2) ...
;;
3) ...
;;
*) echo "Invalid argument"
;;
esac

Resources