I want to check if a string's first char is uppercase, lowercase or anything else. I tried this code but I can't get to the last else although the first two conditions are false.
#!/bin/bash
echo "enter var: "
read var
if [[ {$var::1 =~ [A-Z] ]]
then
echo "UpperCase"
elif [[ {$var::1} =~ [a-z] ]]
then
echo "LowerCase"
else
echo "Digit or a symbol"
fi
exit
When I enter 1hello I get: "LowerCase"
What am I missing here?!
You don't necessarily need to extract the first character, you can compare the whole string to a pattern.
Here, I'm using the POSIX character classes [:upper:] and [:lower:] which I find more descriptive. They also handle non-ASCII letters.
Regex matching:
if [[ $var =~ ^[[:upper:]] ]]; then echo starts with an upper
elif [[ $var =~ ^[[:lower:]] ]]; then echo starts with a lower
else echo does not start with a letter
fi
With shell glob patterns -- within [[...]] the == operator does pattern matching not just string equality
if [[ $var == [[:upper:]]* ]]; then echo starts with an upper
elif [[ $var == [[:lower:]]* ]]; then echo starts with a lower
else echo does not start with a letter
fi
A case statement would work here as well
case "$var" in
[[:upper:]]*) echo starts with an upper ;;
[[:lower:]]*) echo starts with a lower ;;
*) echo does not start with a letter ;;
esac
Neither of your parameter expansions are correct. {$var::1 evaluates to {1hello::1, not 1, and {$var::1} likewise evaluates to {1hello::1}.
The expansion you want is ${var::1}, which does expand to 1 as intended.
You don't need a fancy parameter expansion anyway; you can match against the first character using regular expressions alone
[[ $var =~ ^[a-z] ]]
or pattern-matching
[[ $var = [a-z]* ]]
Regular expressions are not implicitly anchored, so you can use ^ to explicitly match the beginning of the string; the remainder of the string can be ignored.
Pattern matches are implicitly anchored to the start and end of the string, so you need * to match everything (if anything) that follows the initial character of the string.
Related
I am trying to parse a command in shell, and in one of the options I want to save in a variable if a string has "r", "w", "x", one of those, all of them, or a mix, but only these three. No other characters should be allowed!
I tried a case where:
$2 in *r*) ;; *w*) ;; *x*) ;; * ) echo no ;;
esac
But in this case if there is written zr it will pass, as it has an "r". I only want to make it pass as long as it has one of these three, the three of them, or two of them (any kind of combination), but no other characters.
In BASH you can use regex for this check like this:
re='^[rwx]+$'
s='rw'
[[ $s =~ $re ]] && echo "yes" || echo "no"
yes
s='zr'
[[ $s =~ $re ]] && echo "yes" || echo "no"
no
Regex ^[rwx]+$ will allow 1 or more of r or w or x letters.
With extended pattern matching in Bash (shopt -s extglob):
if [[ $var == +([rwx]) ]]; then
echo "Matches!"
else
echo "Does not match!"
fi
The +([rwx]) pattern is "one or more of r, w or x".
I tried the following three codes to detects empty variable.
unset value
if [[ -z ${value} ]]; then
echo "value is judged as empty by [[ -z ]] : value = '${value}'"
fi
if [[ ${value} == ^[[:blank:]]*$ ]]; then
echo "value is judged as empty by [[ == ]] : value = '${value}'"
fi
if echo ${value} | grep -E "^[[:blank:]]*$"; then
echo "value is judged as empty by grep -E "^[[:blank:]]*$" : value = '${value}'"
fi
The results are following,
value is judged as empty by [[ -z ]] : value = ''
value is judged as empty by grep -E ^[[:blank:]]* : value = ''
Why the second one does not work? Please let me know.
Your second one is a pattern, not a regular expression. It only matches strings with at least 3 characters: ^, a single blank character, zero or more arbitrary characters, and $. To match the regular expression representing zero or more blank characters, use the =~ operator.
if [[ $value =~ ^[[:blank:]]*$ ]]; then
I am reading a shell script in Unix.
I have come upon the below line:
if [[ ! $1 =~ ^# ]];
I understand the part which is on left side of equal sign but what does ~^# means.
According to http://wiki.bash-hackers.org/syntax/ccmd/conditional_expression the =~ is:
<STRING> =~ <ERE> <STRING> is checked against the extended regular expression <ERE> - TRUE on a match
So the ^# is a extended regular expression. Since # is not a special character in extended regex. The meaning of the if checks that the string in $1 does not start with #. So on the command line
$ if [[ ! '#' =~ ^# ]]; then echo matches; else echo no match; fi
no match
$ if [[ ! 'b' =~ ^# ]]; then echo matches; else echo no match; fi
matches
The ~ allows to use POSIX regular expression matching (regex).
The ^ is a special character that evaluates the beginning of a line
In your case, ^# means a line beginning with #. Then your condition only takes care of lines that do not begin with #.
In shell scripting, lines beginning with # are comments, that are not evaluated as commands by the shell.
when I compare two strings with single equal “=” ?
and when I compare two strings with double equal “==” ?
for example:
[[ $STR = $STR1 ]]
OR
[[ $STR == $STR1 ]]
Or maybe they are both do exactly the same thing?
[[ $a == z* ]] # True if $a starts with an "z" (pattern matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).
[ $a == z* ] # File globbing and word splitting take place.
[ "$a" == "z*" ] # True if $a is equal to z* (literal matching).
Everything about string comparison you can find here.
You right, both way does exactly the same thing, there is no difference at the execution.
In your conditions, take care to add quotes to your variable's name, bash could throws an error if one of them is null. Add double quotes will pass throught this error by setting variable to empty string "".
[[ "$STR1" = "$STR2" ]]
EDIT : (Thanks to comments below)
Prefer use this syntaxe [ "$STR1" == "$STR2" ] for test and shell convenience. Doubles quotes are better to use and make your condition usable with regular expression as "*.txt" but not even required.
In a bash (version 3.2.48) script I get a string that can be something like:
'XY'
' Y'
'YY'
etc
So, I have either an alphabetic character OR a space (first slot), then the relevant character (second slot). I tried some variation (without grep, sed, ...) like:
if [[ $string =~ ([[:space]]{1}|[[:alpha:]]{1})M ]]; then
and
if [[ $string =~ (\s{1}|.{1})M ]]; then
but my solutions did not always work correctly (matching correctly every combination).
This should work for you:
if [[ $string =~ [[:space:][:alpha:]]M ]]; then
if [[ ${string:1:1} == "M" ]]; then
echo Heureka
fi
or (if you want to do it with patterns)
if [[ $string =~ ([[:space:]]|[[:alpha:]])M ]]; then
echo Heureka
fi
or (even simpler)
if [[ $string == ?M ]]; then
echo Heureka
fi
Without using regular expressions, simply pattern matching is sufficient:
if [[ $string == [[::upper:]\ ]M ]]; then
echo match
fi
Given your example, you want [[:upper:]] rather than merely [[:alpha:]]