This question already has answers here:
Using case for a range of numbers in Bash
(5 answers)
Closed 9 years ago.
i want to do something like ..
if mark is between 80-100 it will show A+
if mark is between 70-79 it will show A
etc
I want to do it with “case in esac” not with if-elif-fi
But how do I do complex expression in case
echo “enter mark”
read mark
case $mark in
(( mark>=80 && mark<=100 ))) echo “A+”
..
..
..
esac
i tried this. it is easy with if-elif-fi but what i should do in the 'case'
thank you.
You don't specify a shell, so let me plug zsh:
#!/bin/zsh
echo “enter mark”
read mark
case $mark in
<80-100>) echo "A+" ;;
<70-79>) echo "A" ;;
...
esac
That said, the POSIX case statement (and the case statement in most shells) is geared towards matching text patterns, not arithmetic comparison. You could use a case statement, but it can get ugly.
case $mark in
[89]?|100) echo "A+" ;;
7?) echo "A" ;;
...
esac
It's not so bad in this case, since you don't have ranges like 65-74, but an if statement would be better.
if (( mark >=80 && mark <=100 )); then
echo "A+"
elif (( mark >=70 )); then
echo "A"
elif ...; then
...
else
...
fi
Use if condition its easier
if [[ ${mark} -ge 80 && ${mark} -le 100 ]]; then
echo "A+"
fi
But if you still need case then you need to specify a pattern
case ${mark} in
8[0-9]|9[0-9]|100)
echo "A+"
esac
In a regular POSIX-ish shell:
echo "enter mark"
read mark
case "$mark" in
([89][0-9]|100) echo "A+";;
(7[0-9]) echo "Grade";;
(6[0-9]) echo "Grade";;
...
esac
The leading open parenthesis on the expressions is optional.
Related
This question already has answers here:
How to check if a string contains a substring in Bash
(29 answers)
Closed 3 years ago.
I am wanting to use a switch/ case statement in bash to check if a file name which is a string contains something but also does not.
Here is my case:
case "$fileName" in
*Failed|!cp*)
echo "match"
;;
esac
But this does not work currently, how can I see if the string matches "Failed" but also does not contain "cp"?
It would be great if this could be done in a switch/ case as well
! has to be followed by a parenthesized list of patterns, not the pattern itself.
| in a case is for OR, not AND. To get AND, you should nest cases.
case "$fileName" in
*Failed)
case "$fileName" in
cp*) ;;
*) echo "match" ;;
esac
;;
esac
Or you could just use if instead of case:
if [[ $filename = *Failed && $filename != cp* ]]
then echo match
fi
Alternatively you can use if and pipes for instance:
if echo 'Failed' | grep -v cp | grep -q Failed ; then
echo Failed without cp
else
echo It's either Winned or cp.
fi
This question already has answers here:
Using getopts to process long and short command line options
(32 answers)
Closed 8 years ago.
I want to use my shell script like this:
myscript.sh -key keyValue
How can I get the keyValue ?
I tried getopts, but it requires the key to be a single letter!
use a manual loop such as:
while :; do
case $1 in
-key)
shift
echo $1
break
;;
*)
break
esac
done
No need to use getopts:
while [ "$#" -gt 0 ]; do
case "$1" in
-key)
case "$2" in
[A-Za-z])
;;
*)
echo "Argument to $1 must be a single letter."
exit 1
;;
esac
keyValue=$2
shift
;;
*)
echo "Invalid argument: $1"
exit 1
;;
esac
shift
done
If your shell is bash it could be simplified like this:
while [[ $# -gt 0 ]]; do
case "$1" in
-key)
if [[ $2 != [A-Za-z] ]]; then
echo "Argument to $1 must be a single letter."
exit 1
fi
keyValue=$2
shift
;;
*)
echo "Invalid argument: $1"
exit 1
;;
esac
shift
done
I really think it's well worth learning getopts: you'll save lots of time in the long run.
If you use getopts then it requires short versions of switches to be a single letter, and prefixed by a single "-"; long versions can be any length, and are prefixed by "--". So you can get exactly what you want using getopts, as long as you're happy with
myscript.sh --key keyValue
This is useful behaviour for getopts to insist on, because it means you can join lots of switches together. If "-" indicates a short single letter switch, then "-key" means the same as "-k -e -y", which is a useful shorthand.
In a shell script, how can I find out if a string is contained within another string.
In bash, I would just use =~, but I am not sure how I can do the same in /bin/sh. Is it possible?
You can use a case statement:
case "$myvar" in
*string*) echo yes ;;
* ) echo no ;;
esac
All you have to do is substitute string for whatever you need.
For example:
case "HELLOHELLOHELLO" in
*HELLO* ) echo "Greetings!" ;;
esac
Or, to put it another way:
string="HELLOHELLOHELLO"
word="HELLO"
case "$string" in
*$word*) echo "Match!" ;;
* ) echo "No match" ;;
esac
Of course, you must be aware that $word should not contain magic glob characters unless you intend glob matching.
You can define a function
matches() {
input="$1"
pattern="$2"
echo "$input" | grep -q "$pattern"
}
to get regular expression matching. Note: usage is
if matches input pattern; then
(without the [ ]).
You can try
lookup 'his' in 'This is a test'
TEST="This is a test"
if [ "$TEST" != "${TEST/his/}" ]
then
echo "$TEST"
fi
This question already has answers here:
How do I prompt for Yes/No/Cancel input in a Linux shell script?
(37 answers)
Closed 2 years ago.
Trying to write a script which will read what a user has imput... I know it's basic but im stuck on the first if..
echo "Please enter yes or no (y/n)?"
read string
if [ $string = "y" -o "n" ]
then
echo "User selected $string"
else
echo "You didn't enter y/n !!!"
fi
I would like it to be if [ $backup = "y" or "n" ]
Any ideas?
Use this syntax in bash :
if [ "a string" = "another one" ] ; then
# Whatever
fi
For multiple conditional statements such as OR, use:
if [ "a string" = "another one" ] || [ "$foo" = "bar" ] ; then
# Whatever
fi
bash also supports the non-standard [[ ... ]] expression, which can process a compound comparison using a single command, rather than 2 [ commands:
if [[ "a string" = "another one" || $foo = "bar" ]]; then
# Whatever
fi
Not the question you actually asked, but... You told the user to enter "yes" or "no" but only test for y or n - sure, you gave them a hint but users are hint-resistant. So maybe a looser test is in order:
echo "Please enter yes or no (y/n)"
read string
case "$string" in
[yY]* | [nN]*) echo "User entered $string" ;;
*) echo "I don't understand '$string'" ;;
esac
That will recognize any variation that begins with Y or N - usually that's good enough, but you could tighten up the tests. Also, since you'll probably want to do something different with a yes or no response you can expand the case (I've also tightened the tests in this one):
case "$string" in
[yY] | [yY][eE][sS]) echo "Here's where you process yes" ;;
[nN] | [nN][oO]) echo "And here you deal with no" ;;
*) echo "I don't understand '$string'" ;;
esac
You could do this with if statements but I find case more readable when more than two alternatives are possible and the test is appropriate to case syntax.
You can also try:
echo "Please enter yes or no (y/n)?"
read string
if [[ "$string" =~ ^(y|n)$ ]]
then
echo "User selected $string"
else
echo "You didn't enter y/n !!!"
fi
I nice solution is would be with case, which is easier to extend if you want to make your input more complex
case $string in
y|n) echo "User selected $string"
;;
*) echo "You didn't enter y/n !!!"
;;
esac
From there you can easily modify it to accept Uppercase or whatever:
case $string in
y|Y) echo "yes, Sir!"
;;
n|N) echo "No, can't do"
;;
*) echo "Say what?"
;;
esac
Check case statements for more info.
This question already has answers here:
Concatenate all arguments and wrap them with double quotes
(6 answers)
Closed 5 years ago.
I would like to concatenate all the arguments passed to my bash script except the flag.
So for example, If the script takes inputs as follows:
./myBashScript.sh -flag1 exampleString1 exampleString2
I want the result to be "exampleString1_exampleString2"
I can do this for a predefined number of inputs (i.e. 2), but how can i do it for an arbitrary number of inputs?
function concatenate_args
{
string=""
for a in "$#" # Loop over arguments
do
if [[ "${a:0:1}" != "-" ]] # Ignore flags (first character is -)
then
if [[ "$string" != "" ]]
then
string+="_" # Delimeter
fi
string+="$a"
fi
done
echo "$string"
}
# Usage:
args="$(concatenate_args "$#")"
This is an ugly but simple solution:
echo $* | sed -e "s/ /_/g;s/[^_]*_//"
You can also use formatted strings to concatenate args.
# assuming flag is first arg and optional
flag=$1
[[ $1 = ${1#-} ]] && unset $flag || shift
concat=$(printf '%s_' ${#})
echo ${concat%_} # to remove the trailing _
nJoy!
Here's a piece of code that I'm actually proud of (it is very shell-style I think)
#!/bin/sh
firsttime=yes
for i in "$#"
do
test "$firsttime" && set -- && unset firsttime
test "${i%%-*}" && set -- "$#" "$i"
done
IFS=_ ; echo "$*"
I've interpreted your question so as to remove all arguments beginning with -
If you only want to remove the beginning sequence of arguments beginnnig with -:
#!/bin/sh
while ! test "${1%%-*}"
do
shift
done
IFS=_ ; echo "$*"
If you simply want to remove the first argument:
#!/bin/sh
shift
IFS=_ ; printf %s\\n "$*"
flag="$1"
shift
oldIFS="$IFS"
IFS="_"
the_rest="$*"
IFS="$oldIFS"
In this context, "$*" is exactly what you're looking for, it seems. It is seldom the correct choice, but here's a case where it really is the correct choice.
Alternatively, simply loop and concatenate:
flag="$1"
shift
the_rest=""
pad=""
for arg in "$#"
do
the_rest="${the_rest}${pad}${arg}"
pad="_"
done
The $pad variable ensures that you don't end up with a stray underscore at the start of $the_rest.
#!/bin/bash
paramCat () {
for s in "$#"
do
case $s in
-*)
;;
*)
echo -n _${s}
;;
esac
done
}
catted="$(paramCat "$#")"
echo ${catted/_/}