Bash: String contains hyphen - string

I am trying to see if string1 contains another string2. I do this in this manner:
a=$(tempfile)
echo "eafg" > $a
if [[ $a == *e* ]]
then
echo "contains"
fi
Now I try to see if a string contains a hyphen:
a=$(tempfile)
echo "22:00:00-02:00" > $a
if [ $a == *-* ]
then
echo "contains"
fi
It doesn't work. I also tried:
if [ $a == *--* ]
if [ $a == *---* ]
if [[ $a == *-* ]]
if [[ $a == *--* ]]
if [[ $a == *---* ]]
With no success...
Thanks in advance

Following piece of code brings problems
a=$(tempfile)
echo "22:00:00-02:00" > $a
Here you are writing to a file $a and then try to do string comparison.
Try following
a="22:00:00-02:00"
if [[ $a == *-* ]]
then
echo "contains"
fi

You redirected the string to a file, so read it from the file while comparing.
The variable a contains the name of the file and not the contents.
Say:
if [ $(<$a) == *-* ];
then
echo "contains"
fi
The following
if [[ $a == *e* ]];
then
echo "contains"
fi
worked for you because the variable holding the name of the file contained the letter e.

Related

Bash: Check if a string contain specific alphabets and comma

I am trying to parse and validate a string in Bash which is comma separated. The expected input is: X4,Y1,Z5
Conditions: The string should have only X,Y or Z alphabets, followed by any number. The string should not have any special characters other than comma. Please suggest.
X4,Y1,Z5 (This is OK)
Z2,y6,X1 (This is OK)
X3Y6,Z8 (This is not OK)
A1,B2,X8 (This is not OK)
N1P8* (This is not OK)
I have tried the following but this is not working as expected.
if [[ ! $str =~ ['!##$%^&*()_+'] ]] && [[ $str =~ [XYZxyz] ]]; then
echo "OK"
else
echo "Not OK"
fi
I suppose there are additional conditions of the problem that were implied but not emphasized, such as:
The numbers may have more then one digit.
Each of X,Y,Z letters should be used exactly once.
With that in mind, I think this code will do:
if [[ "$1" =~ ^[XxYyZz][0-9]+(,[XxYyZz][0-9]+){2}$ ]] &&
[[ "$1" =~ .*[Xx].* ]] &&
[[ "$1" =~ .*[Yy].* ]] &&
[[ "$1" =~ .*[Zz].* ]]
then
echo OK
else
echo Not OK
fi
Test cases:
#!/usr/bin/env bash
check() {
[[ "$1" =~ ^[XxYyZz][0-9]+(,[XxYyZz][0-9]+){2}$ ]] &&
[[ "$1" =~ .*[Xx].* ]] &&
[[ "$1" =~ .*[Yy].* ]] &&
[[ "$1" =~ .*[Zz].* ]]
}
test_check() {
# code - expected exit code
# value - string to test
while read code value; do
check "$value"
if [[ $? == $code ]]; then
echo -e "\e[1;32mPassed:\e[0m $value"
else
echo -e "\e[1;31mFailed:\e[0m $value"
fi
done
}
test_check <<EOF
0 x1,y2,z3
0 X1,Y2,Z3
1 x,y,z
1 1,2,3
1 1x,2y,3z
0 z1,x2,y3
1 a1,b2,c3
1 x1
1 x1,y2 z1
1 x1,x2
1 x1;y2;z3
1 x1,y2
1 x1,y2,y3
0 x100,Y500,z0
0 x011,y015,z0
1 x1,x2,y3,z4
1 x1,y1,z1 .
EOF
P.S.
If any of the X,Y,Z may appear in the string more than once or not appear at all, then [[ "$str" =~ ^[XxYyZz][0-9]+(,[XxYyZz][0-9]+)*$ ]] should work. I added here + for digits to appear one or more times after the letter, and quoted "$str" in case if there's a space in it (or, to be precise, any character from $IFS variable).

Shell script if condition not evaluated for a help info display for the user

I had written a help menu for reference about the usage of a shell script my_script.sh
echo $'\n\n'
echo $(printf '=%.0s' {1..100})
printf ' %.0s' {1..40}
echo "Welcome"
echo $(printf '=%.0s' {1..100})
echo $'\n'
arg=$1
echo "Input : $arg"
echo
if [[ arg -eq "-h" ]] || [[ arg -eq "-H" ]] || [[ arg -eq "-help" ]] || [[ arg -eq "-Help" ]] || [[ arg -eq "--h" ]] || [[ arg -eq "--H" ]] || [[ arg -eq "--help" ]] || [[ arg -eq "--Help" ]]; then
echo "Help menu requested...."
echo $'\n\n'
echo $(printf '~%.0s' {1..100})
printf ' %.0s' {1..43}
echo "Help Menu"
echo $(printf '~%.0s' {1..100})
echo $'\n'
exit 0
else
echo "Executing a program...."
./another_script.sh
fi
When I execute `myscript.sh -h' (or any of the '-' prefixed option), it goes to the if condition, but any other argument doesn't. What am I doing wrong here? I'm new to bash scripts.
Two simple problems with your if:
-eq is for integer comparison, = or == for strings
Use $arg in your if (instead of arg).
But: I would recommend using getopts instead of string comparison. This would make the part more robust, taking care of different ordering of parameters, or when one letter parameters are combined into a single argument.
Unfortunately I do not know the exact reason why your code does not work, but I can offer you a quick fix: You can write "==" instead of "-eq" and prefix your variable "arg" with a dollar sign. Then your script should work fine.
Working example (GNU bash 4.4.19):
arg=$1
if [[ $arg == "-h" ]] || [[ $arg == "-H" ]]; then
echo "Help!"
else
echo "Stop!"
fi
the -eq operation is only used for comparing numbers.
To compare strings uses the operation =
You forgot $ sign for variables arg in Bash, should be $arg
When we use variables in Bash, we should better use double quote.
use #() for multiple strings comparison.
so the if conditions [[ arg -eq "-h" ]] should be [[ "$arg" = "-h" ]]
When comparing a variable with multiple strings, we can use [[ "$arg" = #(-h|-H|--help|--HELP|--h|--H|-help|--HELP) ]].
if [[ "$arg" = #(-h|-H|--help|--HELP|--h|--H|-help|--HELP) ]]; then
echo "Help menu requested...."
echo $'\n\n'
echo $(printf '~%.0s' {1..100})
printf ' %.0s' {1..43}
echo "Help Menu"
echo $(printf '~%.0s' {1..100})
echo $'\n'
exit 0
else
echo "Executing a program...."
./another_script.sh
fi
In addition, we can use boxes(boxes - Command line ASCII boxes unlimited!
) to generate a comment box
cat <<EOF | boxes -a c -d shell -p a5 -s 30x9
HELP MENU
bla bla
EOF
output:
########################################
# #
# #
# HELP MENU #
# #
# bla bla #
# #
# #
########################################

IF statement multiple and or conditions

I am using if statement with multiple condition in bash.
How can I reduce the following line syntax. So that it looks good from design point of you.
if [ "$1" != "-l" ] && [ "$1" != "-a" ] && [ "$1" != "-h" ] && [ "$1" != "" ] && [ "$1" = "-d" ] || [ "$1" = "-mv" ] || [ "$1" = "-dv" ] || [ "$1" = "-mr" ] || [ "$1" = "-dr" ];
Thanks
Use pattern matching.
if [[ $1 && $1 != -[lah] && $1 == -#(d|mv|dv|mr|dr) ]]; then
#(...) is an example of an extended pattern, which should be recognized by default inside [[ ... ]] in recent versions of bash. If you version is not so recent, add shopt -s extglob to the beginning of your script.
In fact, you can drop the $1 && $1 != -[lah] because its truth would be implied by the truth of $1 == -#(...).
if [[ $1 == -#(d|mv|dv|mr|dr) ]]; then
You could also just use a POSIX-compliant case statement:
case $1 of
-d|-mv|-dv|-mr|-dr) echo good option ;;
*) echo bad option ;;
esac
You can create 2 arrays for matching and non matching values and check if element $1 matches any element in the array or not like below.
nonmatch_array=( "-l" "-a" "-h" "" )
match_array=( "-d" "-mv" "-dv" "-mr" "-dr" )
if [ `echo ${match_array[#]} | grep "$1"` ] || ! [ `echo ${nonmatch_array[#]} | grep "$1"` ] ; then
echo "is in array"
else
echo "is not in array"
fi
Hope it should work for you.
First try to limit the length of the code on 1 line.
if [ [ "$1" != "-l" ]
&& [ "$1" != "-a" ]
&& [ "$1" != "-h" ]
&& [ -n "$1" ]
&& ( [ "$1" = "-d" ]
|| [ "$1" = "-mv" ]
|| [ "$1" = "-dv" ]
|| [ "$1" = "-mr" ]
|| [ "$1" = "-dr" ] ) ];
I added braces, to make clear what you mean with the or's.
Now you can combine all matches with a regular expression:
if [[ ! ("$a" =~ ^-(l|a|h|d|)$)
&& "$a" =~ ^-(mv|dv|mr|dr)$ ]]; then
echo "Yes $a matches"
fi
but reconsider what you are testing. The test will only be true when it matches -mv/-dv/-mr/-dr, so you do not need to test for the options lah.
if [[ "$a" =~ ^-(d|mv|dv|mr|dr)$ ]]; then
echo "Yes $a matches"
fi
You can use a variable for extracting the options:
options="d|mv|dv|mr|dr"
if [[ "$a" =~ ^-(${options})$ ]]; then
echo "Yes $a matches"
fi
Everytime the code is becoming hard to read (and also for long code or repeating statements), you should consider using a function.
The next function is short, but hard to read:
options="d|mv|dv|mr|dr"
function checkoption1 {
[[ "$a" =~ ^-(${options})$ ]]
}
checkoption1 "$a" &&
echo "Yes $a matches"
I would choose for a slightly more verbose function. I will include your original tests for lah for showing the possibilities.
# checkoption return 0 for match,
# returns 1 for forbidden option
# returns 2 for undefined option
function checkoption2 {
case "$1" in
-d|-mv|-dv|-mr|-dr) return 0 ;;
-l|-a|-h|"") return 1;;
*) return 2;;
esac
}
checkoption2 "$a" &&
echo "Yes $a matches"
You should make some testruns before accepting your code.
I have made some tests with a small loop (now all answers together)
function checkoption1 {
[[ "$a" =~ ^-(${options})$ ]]
}
# checkoption return 0 for match,
# returns 1 for forbidden option
# returns 2 for undefined option
function checkoption2 {
case "$1" in
-d|-mv|-dv|-mr|-dr) return 0 ;;
-l|-a|-h|"") return 1;;
*) return 2;;
esac
}
for a in -mv mv -mvx -ms -mr -dr; do
if [[ ! ("$a" =~ ^-(l|a|h|)$)
&& "$a" =~ ^-(d|mv|dv|mr|dr)$ ]]; then
echo "Yes $a matches"
fi
if [[ "$a" =~ ^-(d|mv|dv|mr|dr)$ ]]; then
echo "Yes $a matches"
fi
options="d|mv|dv|mr|dr"
if [[ "$a" =~ ^-(${options})$ ]]; then
echo "Yes $a matches"
fi
checkoption1 "$a" &&
echo "Yes $a matches"
checkoption2 "$a" &&
echo "Yes $a matches 2"
done

How do I test if a variable is a string in bash?

I tried the following but without success
[root#OBAMA~]# bash
[root#OBAMA~]# a=HelloWorld
[root#OBAMA~]# [[ $a == [A-Za-z] ]] && echo "YES ITS STRING"
( the command not prints anything )
[root#OBAMA~]# [[ $a == [A-Z][a-z] ]] && echo "YES ITS STRING"
( the command not prints anything )
Change your command lke below.
$ [[ $a =~ [A-Za-z]+ ]] && echo "YES ITS STRING"
YES ITS STRING
Use =~ operator to test an input string against a regex.
Add + next to the character class, so that it would repeat the previous pattern or token one or more times. Here it's unnecessary.
Add anchors , in-order to do an exact string match. [[ $a =~ [A-Za-z] ]] && echo "YES ITS STRING" alone will print the string YES ITS STRING because the variable a contains atleast an alphabet.
$ a="HelloWorld"
$ [[ $a =~ ^[A-Za-z]+$ ]] && echo "YES ITS STRING"
YES ITS STRING
$ a="Hello World"
$ [[ $a =~ ^[A-Za-z]+$ ]] && echo "YES ITS STRING"
$
how do you define "a string"
[[ -n $a ]] && echo variable a is not empty
[[ $a == *[[:alpha:]]* ]] && echo variable a contains a letter
shopt -s extglob failglob
[[ $a == +([[:alpha:]]) ]] && echo variable a only has letters
Your glob expressions are not matching because your checking that your variable contains only 1 character or 2 characters.

When/how to use "==" or "-eq" operator in test?

In the following code I want to compare the command line arguments with the parameters but I am not sure what is the current syntax to compare the arguments with parameters..i.e "==" or "-eq".
#!/bin/bash
argLength=$#
#echo "arg = $1"
if [ argLength==0 ]; then
#Running for the very first
#Get the connected device ids and save it in an array
N=0
CONNECTED_DEVICES=$(adb devices | grep -o '\b[A-Za-z0-9]\{8,\}\b'|sed -n '2,$p')
NO_OF_DEVICES=$(echo "$CONNECTED_DEVICES" | wc -l)
for CONNECTED_DEVICE in $CONNECTED_DEVICES ; do
DEVICE_IDS[$N]="$CONNECTED_DEVICE"
echo "DEVICE_IDS[$N]= $CONNECTED_DEVICE"
let "N= $N + 1"
done
for SEND_DEVICE_ID in ${DEVICE_IDS[#]} ; do
callCloneBuildInstall $SEND_DEVICE_ID
done
elif [ "$1" -eq -b ]; then
if [ $5 -eq pass ]; then
DEVICE_ID=$3
./MonkeyTests.sh -d $DEVICE_ID
else
sleep 1h
callCloneBuildInstall $SEND_DEVICE_ID
fi
elif [ "$1" -eq -m ]; then
echo "Check for CloneBuildInstall"
if [ "$5" -eq pass ]; then
DEVICE_ID=$3
callCloneBuildInstall $SEND_DEVICE_ID
else
echo "call CloneBuildInstall"
# Zip log file and save it with deviceId
callCloneBuildInstall $SEND_DEVICE_ID
fi
fi
function callCloneBuildInstall {
./CloneBuildInstall.sh -d $SEND_DEVICE_ID
}
From help test:
[...]
STRING1 = STRING2
True if the strings are equal.
[...]
arg1 OP arg2 Arithmetic tests. OP is one of -eq, -ne,
-lt, -le, -gt, or -ge.
But in any case, each part of the condition is a separate argument to [.
if [ "$arg" -eq 0 ]; then
if [ "$arg" = 0 ]; then
Why not use something like
if [ "$#" -ne 0 ]; then # number of args should not be zero
echo "USAGE: "
fi
When/how to use “==” or “-eq” operator in test?
To put it simply use == when doing lexical comparisons a.k.a string comparisons but use -eq when having numerical comparisons.
Other forms of -eq (equal) are -ne (not equal), -gt (greater than), -ge (greater than or equal), -lt (lesser than), and -le (lesser than or equal).
Some may also suggest preferring (( )).
Examples:
[[ $string == "something else" ]]
[[ $string != "something else" ]] # (negated)
[[ $num -eq 1 ]]
[[ $num -ge 2 ]]
(( $num == 1 ))
(( $num >= 1 ))
And always use [[ ]] over [ ] when you're in Bash since the former skips unnecessary expansions not related to conditional expressions like word splitting and pathname expansion.

Resources