Bash how to check if string contains '*'? [duplicate] - bash

This question already has answers here:
How to check if string contains characters in regex pattern in shell?
(3 answers)
Closed 4 months ago.
Bash how to check whether a string in bash contains *. Since * is a special character?

if [[ $string == *"*"* ]]; then echo "string contains asterisk"; fi
Within double braces, the == operator does pattern matching. Quoted parts of a pattern are handled as literal strings.
With a regex, * is not special inside a bracket expression, or when quoted:
if [[ $string =~ [*] ]]; then echo "string contains asterisk"; fi
if [[ $string =~ "*" ]]; then echo "string contains asterisk"; fi

You can use grep "\*" filename if you need to check if a string within a file contains a "*".
As * is a special character it is then necessary to use the escape character \.

Related

Regular expression in bash not working in conditional construct in Bash with operator '=~'

The regular expression I have put into the conditional construct (with the =~ operator) would not return the value as I had expected, but when I assign them into two variables it worked. Wondering if I had done something wrong.
Version 1 (this one worked)
a=30
b='^[0-9]+$' #pattern looking for a number
[[ $a =~ $b ]]
echo $?
#result is 0, as expected
Version 2 (this one doesn't work but I thought it is identical)
[[ 30 =~ '^[0-9]+$' ]]
echo $?
#result is 1
Don't quote the regular expression:
[[ 30 =~ ^[0-9]+$ ]]
echo $?
From the manual:
Any part of the pattern may be quoted to force the quoted portion to be matched as a string.
So if you quote the entire pattern, it's treated as a fixed string match rather than a regular expression.

Check in shellscript if a variable is partially the same as a parameter [duplicate]

This question already has answers here:
How to check if a string contains a substring in Bash
(29 answers)
Closed 4 years ago.
So this is admittedly for university, but I can't find the answer anywhere, nor online, nor in the lecture notes.
I basically take a parameter, and have to search, if that is part of a longer string I have already stored:
if [ *$param* = $var ]
then
...
is the part in question. Now what is really weird for me, is that no matter if it says = or !=, the code nested under then never gets executed. I checked every other part of the code very thoroughly, and it all looks to be working fine.
Do you have any ideas what might cause this?
You just need to reverse the arguments. Inside [[ ... ]], =, ==, and != can perform pattern matching if the right-hand operand contains unescaped meta characters like * and ?, or a bracket expression [...].
if [[ $var == *"$param"* ]]; # check if $param is a substring of $var
Your code may or may not have performed pattern matching (depending on the contents of $var, but you were seeing if the string with the value of $param embedded in literal *s matched the value of $var.
For example, [[ foobar == *oba* ]] would succeed, as oba is a substring of foobar. [[ *oba* == foobar ]] would not, since *oba* and foobar are two distinct different strings. [[ *oba* == *oba ]] would also fail, since *oba* is not a string that ends with oba.
I would use grep
if echo $var | grep -q $param; then
echo "found it!"
fi
Try this
if [[ $var =~ $param ]]; then
echo "matches"
fi

Different behavior on escaping double quotes

I have a empty variable. When I do
if [[ -z "$value" ]]; then echo "hello"; fi
the output is hello
However, when I escape double quotes, i.e.
if [[ -z \"$value\" ]]; then echo "hello"; fi
hello is not printed on the screen.
What is the difference between above two commands?
It is because the in the first statement, the variable is expanded and the resulting statement is null.
Whereas in the second it expands to "". To see the difference consider the two echo statements,
$ echo "$value"
$ echo \"$value\"
""
The first one is null where as the second is not.
There are three kind of quotes in Shell.
Single quote(' ')
All special characters between these quotes lose their special meaning.
so echo '$VALUE'
will literally print $VALUEbecause $loses its special meaning
inside single quotes.
double Quotes(" ")
Most special characters between these quotes lose their special meaning with some exceptions like $ among others.
Back Quote ()
Anything in between back quotes would be treated as a command and would be executed.
Backslash
Any character immediately following the backslash loses its special meaning.
so in your case when you say \"$value\" because of backslash double quotes will loose meaning and will be evaluated as it is.
e.g if you have value=34 then \"$value\" will evaluate to "34" with the double quotes. and if value is null as in your case then \"$value\" will evaluate to ""
so it is not null but a string with double quotes and that's why fail your null check.
if [[ -z "$value" ]]; then echo "hello"; fi checks if the string value in the variable $value is non-empty. But if [[ -z \"$value\" ]]; then echo "hello"; fi (assuming $value does not contain whitespace) checks if the string that starts with a " and ends with a " is non-empty. But it never is, because it always contains at least two characters.

Shell script Bash, Check if string starts and ends with single quotes

I need to check if a string starts and ends with a single quote, for example
'My name is Mozart'
What I have is this, which doesn't work
if [[ $TEXT == '*' ]] ;
This does not work either
if [[ $TEXT == /'*/' ]] ;
But if I change it to
if [[ $TEXT == a*a ]] ;
it works for a sentence like 'an amazing apa'. So I Believe it has to do with the single quote sign.
Any ideas on how I can solve it?
With a regex:
if [[ $TEXT =~ ^\'.*\'$ ]]
With globbing:
if [[ $TEXT == \'*\' ]]
I am writing the complete bash script so you won't have any confusion:
#! /bin/bash
text1="'helo there"
if [[ $text1 =~ ^\'.*\'$ ]]; then
echo "text1 match"
else
echo "text1 not match"
fi
text2="'hello babe'"
if [[ $text2 =~ ^\'.*\'$ ]]; then
echo "text2 match"
else
echo "text2 not match"
fi
Save the above script as
matchCode.sh
Now run it as:
./matchCode
output:
text1 not match
text2 match
Ask if you have any confusion.
Cyrus' helpful answer solves your problem as posted.
However, I suspect you may be confused over quotes that are part of the shell syntax vs. quotes that are actually part of the string:
In a POSIX-like shell such as Bash, 'My name is Mozart' is a single-quoted string whose content is the literal My name is Mozart - without the enclosing '. That is, the enclosing ' characters are a syntactic elements that tell the shell that everything between them is the literal contents of the string.
By contrast, to create a string whose content is actually enclosed in ' - i.e., has embedded ' instances, you'd have to use something like: "'My name is Mozart'". Now it is the enclosing " instances that are the syntactic elements that bookend the string content.
Note, however, that using a "..." string (double quotes) makes the contents subject to string interpolation (expansion of embedded variable references, arithmetic and command substitutions; none in the case at hand, however), so it's important to know when to use '...' (literal strings) vs. "..." (interpolated strings).
Embedding ' instances in '...' strings is actually not supported at all in POSIX-like shells, but in Bash, Ksh, and Zsh there's another string type that allows you to do that: ANSI C-quoted strings, $'...', in which you can embed ' escaped as \': $'\'My name is Mozart\''
Another option is to use string concatenation: In POSIX-like shells, you can place substrings employing different quoting styles (including unquoted tokens) directly next to one another in order to form a single string: "'"'My Name is Mozart'"'" would also give you a string with contents 'My Name is Mozart'.
POSIX-like shells also allow you to escape individual, unquoted characters (meaning: neither part of a single- nor a double-quoted string) with \; therefore, \''My name is Mozart'\' yields the same result.
The behavior of Bash's == operator inside [[ ... ]] (conditionals) may have added to the confusion:
If the RHS (right-hand side - the operand to the right of operator ==) is quoted, Bash treats it like a literal; only unquoted strings (or variable references) are treated as (glob-like) patterns:
'*' matches literal *, whereas * (unquoted!) matches any sequence of characters, including none.
Thus:
[[ $TEXT == '*' ]] would only ever match the single, literal character *.
[[ $TEXT == /'*/' ]], because it mistakes / for the escape character - which in reality is \ - would only match literal /*/ (/'*/' is effectively a concatenation of unquoted / and single-quoted literal */).
[[ $TEXT == a*a ]], due to using an unquoted RHS, is the only variant that actually performs pattern matching: any string that starts with a and ends with a is matched, including aa (because unquoted * represents any sequence of characters).
To verify that Cyrus' commands do work with strings whose content is enclosed in (embedded) single quotes, try these commands, which - on Bash, Ksh, and Zsh - should both output yes.
[[ "'ab'" == \'*\' ]] && echo yes # pattern matching, indiv. escaped ' chars.
[[ "'ab'" =~ ^\'.*\'$ ]] && echo yes # regex operator =~

Search in string for multiple array values

I'm looking at a simple for loop with the following logic:
variable=`some piped string`
array_value=(1.1 2.9)
for i in ${array_value[#]}; do
if [[ "$variable" == *some_text*"$array_value" ]]; then
echo -e "Info: Found a matching string"
fi
The problem is that I cannot get this to show me when it finds either the string ending in 1.1 or 2.9 as sample data.
If I do an echo $array_value in the for loop I can see that the array values are being taken so its values are being parsed, though the if loop doesn't return that echo message although the string is present.
LE:
Based on the comments received I've abstracted the code to something like this, which still doesn't work if I want to use wildcards inside the comparison quote
versions=(1.1 2.9)
string="system is running version:2.9"
for i in ${versions[#]}; do
if [[ "$string" == "system*${i}" ]]; then
echo "match found"
fi
done
Any construction similar to "system* ${i}" or "* ${i}" will not work, though if I specify the full string pattern it will work.
The problem with the test construct has to you with your if statement. To construct the if statement in a form that will evaluate, use:
if [[ "$variable" == "*some_text*${i}" ]]; then
Note: *some_text* will need to be replaced with actual text without * wildcards. If the * is needed in the text, then you will need to turn globbing off to prevent expansion by the shell. If expansion is your goal, then protect the variable i by braces.
There is nothing wrong with putting *some_text* up against the variable i, but it is cleaner, depending on the length of some_text, to assign it to a variable itself. The easiest way to accommodate this would be to define a variable to hold the some_text you are needing. E.g.:
prefix="some_text"
if [[ "$variable" == "${prefix}${i}" ]]; then
If you have additional questions, just ask.
Change "system*${i}" to system*$i.
Wrapping with quotes inside [[ ... ]] nullifies the wildcard * by treating it as a literal character.
Or if you want the match to be assigned to a variable:
match="system*"
you can then do:
[[ $string == $match$i ]]
You actually don't need quotes around $string either as word splitting is not performed inside [[ ... ]].
From man bash:
[[ expression ]]
...
Word splitting and pathname expansion are not
performed on the words between the [[ and ]]
...
Any part of the pattern may be quoted to force
the quoted portion to be matched as a string.

Resources