How to make a regex match with grep in shell script? - shell

I am trying to create a shell script that matches a string with a predefined regex. I have the following code:
#!/bin/sh
name="Name of string to match. #123"
(echo "$name" | grep -Eq ^[#]\d+$) && echo "matched" || echo "did not
match"
I am always getting a "did not match" message, even though I think the string in the example should match the regex. Can anyone realize what I am doing wrong? Is the regex wrong or is it the call to grep?

Wrap the regex in quotes:
(echo "$name" | grep -Eq '^[#]\d+$') && echo "matched" || echo "did not match"
If you expect the sample input to match, remove the start-of-input anchor ^, ie use '[#]\d+$' as your regex (which would match anything ending in # then digits).

Related

How to count if there is a string of 3 or more chars in a string bash shell

I am writing a password check script and I would like to be able to check if password includes a string of 3 or more of the same characters (aaa, babbb, asj111) all would be a "bad password". I have tried
grep -E '(.)\1{2,}' $password
but I want this in an if statement to then do something if I find more than 3 characters. All help is appreciated!
Use the return code of grep:
if grep -q '\(.\)\1\1' <<< "$password"; then
echo "Bad password!"
# Do something, like exit 1
fi
The -q option is to keep grep quiet. I didn't use the -E (extended) option, use it if you want.
Put your pattern in a variable. It matches any character, then the same character twice again (so three times in total).
pattern='(.)\1{2}'
Then test it with the bash regex comparison operator =~
[[ $password =~ $pattern ]] && echo "bad password"

Bash - check for a string in file path

How can I check for a string in a file path in bash? I am trying:
if [[$(echo "${filePathVar}" | sed 's#//#:#g#') == *"File.java"* ]]
to replace all forward slashes with a colon (:) in the path. It's not working. Bash is seeing the file path string as a file path and throws the error "No such file or directory". The intention is for it to see the file path as a string.
Example: filePathVar could be
**/myloc/src/File.java
in which case the check should return true.
Please note that I am writing this script inside a Jenkins job as a build step.
Updates as of 12/15/15
The following returns Not found, which is wrong.
#!/bin/bash
sources="**/src/TESTS/A.java **/src/TESTS/B.java"
if [[ "${sources}" = ~B.java[^/]*$ ]];
then
echo "Found!!"
else
echo "Not Found!!"
fi
The following returns Found which also also wrong (removed the space around the comparator =).
#!/bin/bash
sources="**/src/TESTS/A.java **/src/TESTS/C.java"
if [[ "${sources}"=~B.java[^/]*$ ]];
then
echo "Found!!"
else
echo "Not Found!!"
fi
The comparison operation is clearly not working.
It is easier to use bash's builtin regex matching facility:
$ filePathVar=/myLoc/src/File.java
if [[ "$filePathVar" =~ File.java[^/]*$ ]]; then echo Match; else echo No Match; fi
Match
Inside [[...]], the operator =~ does regex matching. The regular expression File.java[^/]* matches any string that contains File.java optionally followed by anything except /.
It worked in a simpler way as below:
#!/bin/bash
sources="**/src/TESTS/A.java **/src/TESTS/B.java"
if [[ $sources == *"A.java"* ]]
then
echo "Found!!"
else
echo "Not Found!!"
fi

BASH: Everything but not slash? IF STATEMENT (STRING COMPARISION)

I'm trying to match any strings that start with /John/ but does not contain / after /John/
if
[ $string == /John/[!/]+ ]; then ....
fi
This is what I got and it doesn't seem to be working.
So I tried
if
[[ $string =~ ^/John/[!/]+$ ]]; then ....
fi
It still didn't work, and so I changed it to
if
[[ $string =~ /John/[^/] ]]; then ....
fi
It worked but will match with all the strings that has / behind /John/ too.
For bash you want [[ $string =~ /John/[^/]*$ ]] -- the end-of-line anchor ensures there are no slashes after the last acceptable slash.
How about "the string starts with '/John/' and doesn't contain any slashes after '/John/'"?
[[ $string = /John/* && $string != /John/*/* ]]
Or you could compare against a parameter expansion that only expands if the conditions are met. This says "after stripping off everything including and after the last slash, the string is /John":
[[ ${string%/*} = /John ]]
In fact, this last solution is the only entirely POSIXLY_STRICT one I can come up with without multiple test expressions.
[ "${string%/*}" = /John ]
By the way, your problem is probably simply be using double-equals inside a single-bracket test expression. bash actually does accept them inside double-bracket test expressions, but a single equals is a better idea.
You can also use plain old grep:
string='/John Lennon/Yoko Ono'
if echo "$string" | grep -q "/John[^/]" ; then
echo "matched"
else
echo "no match found"
fi
This only fails if /John is at the very end of the string... if that's a possibility then you can tweak to handle that case, for instance:
string='/John Lennon/Yoko Ono'
if echo "$string" | grep -qP "(/John[^/])|(/John$)" ; then
echo "matched"
else
echo "no match found"
fi
Not sure what language you're using, but normal negative character classes are prefixed with a ^
e.g.
[^/]
You can also put in start/end qualifiers (clojure example, so Java's regex engine). Usually ^ at beginning and $ at end.
user => (re-matches #"^/[a-zA-Z]+[^/]$" "/John/")
nil

case insensitive string comparison in bash

The following line removes the leading text before the variable $PRECEDING
temp2=${content#$PRECEDING}
But now i want the $PRECEDING to be case-insensitive. This works with sed's I flag. But i can't figure out the whole cmd.
No need to call out to sed or use shopt. The easiest and quickest way to do this (as long as you have Bash 4):
if [ "${var1,,}" = "${var2,,}" ]; then
echo "matched"
fi
All you're doing there is converting both strings to lowercase and comparing the results.
Here's a way to do it with sed:
temp2=$(sed -e "s/^.*$PRECEDING//I" <<< "$content")
Explanation:
^.*$PRECEDING: ^ means start of string, . means any character, .* means any character zero or more times. So together this means "match any pattern from start of string that is followed by (and including) string stored in $PRECEDING.
The I part means case-insensitive, the g part (if you use it) means "match all occurrences" instead of just the 1st.
The <<< notation is for herestrings, so you save an echo.
The only bash way I can think of is to check if there's a match (case-insensitively) and if yes, exclude the appropriate number of characters from the beginning of $content:
content=foo_bar_baz
PRECEDING=FOO
shopt -s nocasematch
[[ $content == ${PRECEDING}* ]] && temp2=${content:${#PRECEDING}}
echo $temp2
Outputs: _bar_baz
your examples have context-switching techniques.
better is (bash v4):
VAR1="HELLoWORLD"
VAR2="hellOwOrld"
if [[ "${VAR1^^}" = "${VAR2^^}" ]]; then
echo MATCH
fi
link: Converting string from uppercase to lowercase in Bash
If you don't have Bash 4, I find the easiest way is to first convert your string to lowercase using tr
VAR1=HelloWorld
VAR2=helloworld
VAR1_LOWER=$(echo "$VAR1" | tr '[:upper:]' '[:lower:]')
VAR2_LOWER=$(echo "$VAR2" | tr '[:upper:]' '[:lower:]')
if [ "$VAR1_LOWER" = "$VAR2_LOWER" ]; then
echo "Match"
else
echo "Invalid"
fi
This also makes it really easy to assign your output to variables by changing your echo to OUTPUT="Match" & OUTPUT="Invalid"

Shell command - condition based on output of command?

I'm trying to run some shell command if a string is not present in a text file. If I paste this line into the command line if gives me an error.
if [ $(cat textfile.txt | grep "search string") -eq "" ]; then; echo "some string"; fi;
Error:
-bash: [: -eq: unary operator expected
If you use [] for comparison you need to use = instead of -eq. You also need some quotes.
if [ "$(cat textfile.txt | grep 'search string')" = "" ]; then; echo "some string"; fi;
Note that grep can take a filename as argument so the cat is unnecessary. You can also directly use the return value of grep: grep returns 1 if the search string is not found.
if [ "$(grep 'search string' textfile.txt)" ]; then
echo "some string";
fi
An even more compact way would be to use logical and &&.
grep "search string" textfile.txt && echo "some string"
The grep command will return 0 if the requested lines are found (1 if not, 2 if an error), so you can just use:
grep "search string" textfile.txt >/dev/null 2>&1
if [[ $? -ne 0 ]] ; then
echo 'Not found'
fi
If you really wanted to use strings (and you probably shouldn't), you should quote them so that you don't get too many arguments for the [ command:
if [ "$(cat textfile.txt | grep 'search string')" == "" ] ; then
echo "It's not there!"
fi
grep -F -q -e 'search string' textfile.txt || echo 'Not found'
Note:
-F prevents the interpretation of the search string as a regular expression.
-q suppresses all output and returns immediately after the first instance was found, making the search much faster if the string occurs at the beginning of a large file.
-e specifies the pattern explicitly, allowing patterns that start with a dash.
Use single quotes unless you want variable substitutions.
No need for the square brackets in this case. Since [ is actually a command, any command can be used where you would use it. So here, we can use grep. There's no need to use cat since grep will accept filenames as arguments. Also, you have two too many semicolons.
if grep -q "search string" textfile.txt; then echo "some string"; fi
or
if grep "search string" textfile.txt > /dev/null 2>&1; then echo "some string"; fi

Resources