I tried to check the following case:
#!/bin/bash
line="abc"
if [[ "${line}" != [a-z] ]]; then
echo INVALID
fi
And I get INVALID as output. But why?
It's no check if $line contains only a characters in the range [a-z] ?
Use the regular expression matching operator =~:
#!/bin/bash
line="abc"
if [[ "${line}" =~ [^a-zA-Z] ]]; then
echo INVALID
fi
Works in any Bourne shell and wastes no pipes/forks:
case $var in
("") echo "empty";;
(*[!a-z]*) echo "contains a non-alphabetic";;
(*) echo "just alphabetics";;
esac
Use [!a-zA-Z] if you want to allow upper case as well.
Could you please try following and let me know if this helps you.
line="abc"
if echo "$line" | grep -i -q '^[a-z]*$'
then
echo "MATCHED."
else
echo "NOT-MATCHED."
fi
Pattern matches are anchored to the beginning and end of the string, so your code checks if $line is not a single lowercase character. You want to match an arbitrary sequence of lowercase characters, which you can do using extended patterns:
if [[ $line != #([a-z]) ]]; then
or using the regular-expression operator:
if ! [[ $line =~ ^[a-z]+$ ]]; then # there is no negative regex operator like Perl's !~
Why? Because != means "not equal", thats why. You tell bash to compare abc with [a-z]. They are not equal.
Try echo $line | grep -i -q -x '[a-z]*'.
The flag -i makes grep case insensitive.
The flag -x means match the whole line.
The flag -q means print nothing to stdout, just return 1 or 0.
Related
I am taking baby steps at learning bash and I am developing a piece of code which takes an input and checks if it contains any spaces. The idea is that the variable should NOT contain any spaces and the code should consequently echo a suitable message.
Try this:
#!/bin/bash
if [[ $1 = *[[:space:]]* ]]
then
echo "space exist"
fi
You can use grep, like this:
echo " foo" | grep '\s' -c
# 1
echo "foo" | grep '\s' -c
# 0
Or you may use something like this:
s=' foo'
if [[ $s =~ " " ]]; then
echo 'contains space'
else
echo 'ok'
fi
You can test simple glob patterns in portable shell by using case, without needing any external programs or Bash extensions (that's a good thing, because then your scripts are useful to more people).
#!/bin/sh
case "$1" in
*' '*)
printf 'Invalid argument %s (contains space)\n' "$1" >&2
exit 1
;;
esac
You might want to include other whitespace characters in your check - in which case, use *[[:space:]]* as the pattern instead of *' '*.
You can use wc -w command to check if there are any words. If the result of this output is a number greater than 1, then it means that there are more than 1 words in the input. Here's an example:
#!/bin/bash
read var1
var2=`echo $var1 | wc -w`
if [ $var2 -gt 1 ]
then
echo "Spaces"
else
echo "No spaces"
fi
Note: there is a | (pipe symbol) which means that the result of echo $var1 will be given as input to wc -w via the pipe.
Here is the link where I tested the above code: https://ideone.com/aKJdyN
You could use parameter expansion to remove everything that isn't a space and see if what's left is the empty string or not:
var1='has space'
var2='nospace'
for var in "$var1" "$var2"; do
if [[ ${var//[^[:space:]]} ]]; then
echo "'$var' contains a space"
fi
done
The key is [[ ${var//[^[:space:]]} ]]:
With ${var//[^[:space:]]}, everything that isn't a space is removed from the expansion of $var.
[[ string ]] has a non-zero exit status if string is empty. It's a shorthand for the equivalent [[ -n string ]].
We could also quote the expansion of ${var//[^[:space:]]}, but [[ ... ]] takes care of the quoting for us.
String:
name#gmail.com
Checking for:
#
.com
My code
if [[ $word =~ "#" ]]
then
if [[ $word =~ ".com" || $word =~ ".ca" ]]
My problem
name#.com
The above example gets passed, which is not what I want. How do I check for characters (1 or more) between "#" and ".com"?
You can use a very very basic regex:
[[ $var =~ ^[a-z]+#[a-z]+\.[a-z]+$ ]]
It looks for a string being exactly like this:
at least one a-z char
#
at least one a-z char
.
at least one a-z char
It can get as complicated as you want, see for example Email check regular expression with bash script.
See in action
$ var="a#b.com"
$ [[ $var =~ ^[a-z]+#[a-z]+\.[a-z]+$ ]] && echo "kind of valid email"
kind of valid email
$ var="a#.com"
$ [[ $var =~ ^[a-z]+#[a-z]+\.[a-z]+$ ]] && echo "kind of valid email"
$
why not go for other tools like perl:
> echo "x#gmail.com" | perl -lne 'print $1 if(/#(.*?)\.com/)'
gmail
The glob pattern would be: [[ $word == ?*#?*.#(com|ca) ]]
? matches any single character and * matches zero or more characters
#(p1|p2|p3|...) is an extended globbing pattern that matches one of the given patterns. This requires:
shopt -s extglob
testing:
$ for word in #.com #a.ca a#.com a#b.ca a#b.org; do
echo -ne "$word\t"
[[ $word == ?*#?*.#(com|ca) ]] && echo matches || echo does not match
done
#.com does not match
#a.ca does not match
a#.com does not match
a#b.ca matches
a#b.org does not match
I want to check the following condition, but it should be case insensitive.
if [ "SPP" == $1 ]
Is there anyway I can do it using regex.
You can also do the following:
#!/bin/bash
myParam=`echo "$1" | tr 'a-z' 'A-Z'`
if [ "SPP" == "$myParam" ]; then
echo "Is the same"
else
echo "It is not the same"
fi
This script will automatically converts user input to uppercase before making any string comparison. By doing so, you will not have to use regex for case insensitive string comparison.
Hope it helps.
Better late than never...
If that's ksh93, use the ~(i:...) case-insensitive globbing sub-pattern:
if [[ $1 == *~(i:spp)* ]]; then
: matched.
fi
For ksh88 (also the ksh clones), use an intermediary variable typeset -u'd to force upper-case:
typeset -u tocheck=$1
if [[ $tocheck == *SPP* ]]; then
: matched
fi
You can use:
shopt -s nocasematch
For case insensitive matching in BASH.
Alternatively this should also work:
[[ "$1" == [sS][pP][pP] ]]
If I have a string var="root/Desktop", how can I determine whether var var contains a '/' character?
Bash can match against regular expressions with =~, try:
[[ $var =~ "/" ]] && echo "contains a slash"
The following would work
[[ "$var" = */* ]]
The portable solution that works in any Bourne-heritage shell and needs no expensive forks or pipes:
case $var in
(*/*) printf 'Has a slash.\n';;
(*) printf 'No slash.\n';;
esac
echo "${var1}" | grep '/' should work.
I
write the following syntax (part of my ksh script)
to check if the first word of LINE=star
and the second word is car
[[ ` echo $LINE | awk '{print $1}' ` = star ]] && [[ ` echo $LINE | awk '{print $2}' ` = car ]] && print "match"
I need other simple smart and shorter solution then my syntax.
from awk,perl or sed(if it possible to use echo only once or better if we cant not use echo, because I need to save time to minimum)
can I get some ideas?
you don't actually need to call any external tools
set -f
set -- $LINE
case "$1 $2" in
"star car")
echo "match";;
esac
You don't need an external process at all:
[[ $LINE == *([ ])star+([ ])car?([ ]*) ]]
If you also need to extract the first word sometimes (warning, typed directly into the browser):
LINE=${LINE##+[ ]} # strip leading spaces
first_word=${LINE%%[ ]*}
if [[ $LINE = *[ ]* ]]; then
LINE_minus_first_word=${LINE##*+([ ])}
else
LINE_minus_first_word=''
fi
Add a tab inside the brackets if they may appear in $LINE.
set -o noglob
words=($LINE)
[[ "${words[0]} ${words[1]}" == "star car" ]] && print "match"
Edit:
Using ksh and Bash's regex matching (Bash >= version 3.2):
pattern='^[[:blank:]]*star[[:blank:]]+car([[:blank:]]+|$)'
[[ $LINE =~ $pattern ]] && print "match"
You can do:
[[ ` echo $LINE | awk '{printf("%s:%s",$1,$2)}'` = star:car ]] && print "match"