Changing the bash =~ operator to a sh compatible argument - regex

So i am running a bash script in coreos and thus I do not have /bin/bash however I do have /bin/sh. Now sh has been fine until I was using someone elses bash script and they have the following line.
if [[ "$file" =~ ^https?:// ]]; then
and my os complained with sh: =~: unknown operand now i assume this mean that the ~= opeator is not compatible with sh but there has to be some other way to do this form looking on SO I discovered that ~= is sometype of regular expressions operator. My question is this then can I replace ~= with something? Note: I have grep on my machine.

I have grep on my machine
Going by the above line, you could write a simple conditional using an if statement as
if echo "$file" | grep -Eq "^https?://"; then
printf 'regex matches\n'
fi
The regex match in grep uses ERE (Extended Regular Expressions) which is available in any POSIX compliant grep that you have installed. The -q just suppresses the normal stdout printed but just returns an exit code to know if the match was successful.
Even if some package of grep you have doesn't have -E allowed, just use the basic regular expressions support, but deprive ? of its special value and pass it literally
if echo "$file" | grep -q "^https\?://"; then

You could rewrite this as a case command:
case "$file" in
http://* | https://* )
# ...
;;
esac

You can call out to expr which does basic regex matching:
if expr match "$file" 'https\?://'; then
The pattern is implicitly anchored to the start of the string.

Related

Executing git-hooks on windows errors out

So,
I have written a simple git-hooks for pre-push which works just fine on Linux or Mac, but doesn't work on Windows.
Script:
Tries to match the commit message with a regular expression, and should return 0 if matches or else exit.
Based on the articles I read, they say that the hook should just work.
Command:
if [[ "$message" =~ "$regular_expression" ]];
Error:
.git/hooks/pre-push: line 6: conditional binary operator expected
.git/hooks/pre-push: line 6: syntax error near `=~'
.git/hooks/pre-push: line 6: ` if [[ "$message" =~ "$regular_expression" ]]; then'
So apparently it seems to be failing on "[[" and "]]".
Now I have also tried removing the double brackets and keep only one.
Command:
if [ "$message" =~ "$regular_expression" ];
Error:
.git/hooks/pre-push: line 6: [: =~: binary operator expected
This message is flawed: TRY-1 Sample
Does anybody know how to solve this issue ?
The =~ construct in bash conditional expressions is not supported in the version of bash shipped with Git for Windows. It looks like the =~ operator was introduced in bash 3.0 but while Git for Windows is using bash 3.1 it seems to be missing this operator.
Possibly $(echo $message | grep "$regexp") will work as a substitute. eg:
$ bash -c '[[ "hello" =~ "^h" ]]'
bash: -c: line 0: conditional binary operator expected
bash: -c: line 0: syntax error near `=~'
bash: -c: line 0: `[[ "hello" =~ "^h" ]]'
$ bash -c '[ $(echo hello | grep "^h") ] && echo matched || echo nomatch'
matched
Update
Here is an example script that works to match something similar using the Git for Windows bash:
#!/bin/bash
#
# grep returns 0 on matching something, 1 whn it fails to match
msg='TEST-111 Sample'
re='([A-Z]{2,8}-[0-9]{1,4}[[:space:]])+[A-Za-z0-9]+[[:space:]]*[A-Za-z0-9]+$'
rx='^([A-Z]{2,8}-[0-9]{1,4})[[:space:]][[:alnum:]]+$'
echo $msg | grep -qE "$rx"
[ $? = 0 ] && echo matched || echo nomatch
This script returns matched for the sample phrase using the second regular expression. Its not really clear what the original expression is attempting to match up -- looks like multiple words so I'm not sure why you don't just match .*$. However, this shows a way to try out the regexp. Note: we are using extended regular expressions ([[:space:]]) so we have to use grep -E. Also we have to take some care about quoting as $ is being used in the regexp.

Regex word boundaries in double bracket version of test

It seems that I can't get word boundaries to work in [[:
$ echo foo | md5sum
d3b07384d113edec49eaa6238ad5ff00 -
$ [[ "$(echo foo | md5sum)" =~ ^d3b07384d113edec49eaa6238ad5ff00 ]] && echo ok
ok
$ [[ "$(echo foo | md5sum)" =~ ^d3b07384d113edec49eaa6238ad5ff00\b ]] && echo ok
$ ## no output
Are word boundaries not accepted in [[? Or am I missing something?
This seems to work, although it's a bit verbose:
[[ "$(echo foo | md5sum)" =~ $(echo '^d3b07384d113edec49eaa6238ad5ff00\b') ]] && echo ok
The problem seems related to the backslash losing the meaning you intend when interpreted by the shell. There's probably some incantation of quoting that would eliminate the issue, but for me it's sometimes just easier to dump the output of a construct into Perl for further processing.
If you can accept a solution that invokes Perl on your system, this works:
echo foo | md5sum | perl -nE 'say "ok" if m/^\bd3b07384d113edec49eaa6238ad5ff00\b/'
If you're stuck with a Perl that predates v5.10, then this:
echo foo | md5sum | perl -lne 'print "ok" if m/^\bd3b07384d113edec49eaa6238ad5ff00\b/'
The solution is fairly self-explanatory if you read through perlrun, which explains what the various command line switches do. We're using -n to cause Perl to process some input, -E to tell Perl to evaluate some code using modern (5.10+) features (say), and the rest just reads as you would expect.
For older Perl versions (pre-5.10), say wasn't available, so the command line switches change to -l, -n, and -e: The first strips newlines from input (not useful), and adds them to output (useful, because print doesn't do that, where the newer say does). And the -e to evaluate some code using pre-5.10 semantics.

Regex and if in shell script

my programs starts some services and store its output in tmp variable and I want to match the variable's content if it starts with FATAL keyword or not? and if it contains I will print Port in use using echo command
For example if tmp contains FATAL: Exception in startup, exiting.
I can do it by sed: echo $tmp | sed 's/^FATAL.*/"Port in use"/'
but I want to use the builtin if to match the pattern.
How can I use the shell built in features to match REGEX?
POSIX shell doesn't have a regular expression operator for UNIX ERE or PCRE. But it does have the case keyword:
case "$tmp" in
FATAL*) doSomethingDrastic;;
*) doSomethingNormal;;
esac
You didn't tag the question bash, but if you do have that shell you can do some other kinds of pattern matching or even ERE:
if [[ "$tmp" = FATAL* ]]; then
…
fi
or
if [[ $tmp =~ ^FATAL ]]; then
…
fi
if [ -z "${tmp%FATAL*}" ]
then echo "Start with"
else
echo "Does not start with"
fi
work on KSH, BASH under AIX. Think it's also ok under Linux.
It's not a real regex but the limited regex used for file matching (internal to the shell, not like sed/grep/... that have their own version inside) of the shell. So * and ? could be used

Bash regex for strong password

How can I use the following regex in a BASH script?
(?=^.{8,255}$)((?=.*\d)(?!.*\s)(?=.*[A-Z])(?=.*[a-z]))^.*
I need to check the user input(password) for the following:
at least one Capital Letter.
at least one number.
at least one small letter.
and the password should be between 8 and 255 characters long.
If your version of grep has the -P option it supports PCRE (Perl-Compatible Regular Expressions.
grep -P '(?=^.{8,255}$)(?=^[^\s]*$)(?=.*\d)(?=.*[A-Z])(?=.*[a-z])'
I had to change your expression to reject spaces since it always failed. The extra set of parentheses didn't seem necessary. I left off the ^.* at the end since that always matches and you're really only needing the boolean result like this:
while ! echo "$password" | grep -P ...
do
read -r -s -p "Please enter a password: " password
done
I'm don't think that your regular expression is the best (or correct?) way to check the things on your list (hint: I'd check the length independently of the other conditions), but to answer the question about using it in Bash: use the return value of grep -Eq, e.g.:
if echo "$candidate_password" | grep -Eq "$strong_pw_regex"; then
echo strong
else
echo weak
fi
Alternatively in Bash 3 and later you can use the =~ operator:
if [[ "$candidate_password" =~ "$strong_pw_regex" ]]; then
…
fi
The regexp syntax of grep -E or Bash does not necessarily support all the things you are using in your example, but it is possible to check your requirements with either. But if you want fancier regular expressions, you'll probably need to substitute something like Ruby or Perl for Bash.
As for modifying your regular expression, check the length with Bash (${#candidate_password} gives you the length of the string in the variable candidate_password) and then use a simple syntax with no lookahead. You could even check all three conditions with separate regular expressions for simplicity.
These matches are connected with the logical AND operator, which means the only good match is when all of them match.
Therefore the simplest way is to match those conditions chained, with the previous result piped into the next expression. Then if any of the matches fail, the entire expression fails:
$echo "tEsTstr1ng" | egrep "^.{8,255}"| egrep "[ABCDEFGHIJKLMNOPQRSTUVWXYZ]"| egrep "[abcdefghijklmnopqrstuvwxyz"] | egrep "[0-9]"
I manually entered all characters instead of "[A-Z]" and "[a-z]" because different system locales might substitute them as [aAbBcC..., which is two conditions in one match and we need to check for both conditions.
As shell script:
#!/bin/sh
a="tEsTstr1ng"
b=`echo $a | egrep "^.{8,255}" | \
egrep "[ABCDEFGHIJKLMNOPQRSTUVWXYZ]" | \
egrep "[abcdefghijklmnopqrstuvwxyz"] | \
egrep "[0-9]"`
# now featuring W in the alphabet string
#if the result string is empty, one of the conditions has failed
if [ -z $b ]
then
echo "Conditions do not match"
else
echo "Conditions match"
fi
grep with -E option uses the Extended regular expression(ERE)From this documentation ERE does not support look ahead.
So you can use Perl for this as:
perl -ne 'exit 1 if(/(?=^.{8,255}$)((?=.*\\d)(?=.*[A-Z])(?=.*[a-z])|(?=.*\\d)(?=.*[^A-Za-z0-9])(?=.*[a-z])|(?=.*[^A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z])|(?=.*\\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))^.*/);exit 0;'
Ideone Link
I get that you are looking for regex, but have you consider doing it through PAM module?
dictionary
quality
There might be other interesting modules.

Return a regex match in a Bash script, instead of replacing it

I just want to match some text in a Bash script. I've tried using sed but I can't seem to make it just output the match instead of replacing it with something.
echo -E "TestT100String" | sed 's/[0-9]+/dontReplace/g'
Which will output TestTdontReplaceString.
Which isn't what I want, I want it to output 100.
Ideally, it would put all the matches in an array.
edit:
Text input is coming in as a string:
newName()
{
#Get input from function
newNameTXT="$1"
if [[ $newNameTXT ]]; then
#Use code that im working on now, using the $newNameTXT string.
fi
}
You could do this purely in bash using the double square bracket [[ ]] test operator, which stores results in an array called BASH_REMATCH:
[[ "TestT100String" =~ ([0-9]+) ]] && echo "${BASH_REMATCH[1]}"
echo "TestT100String" | sed 's/[^0-9]*\([0-9]\+\).*/\1/'
echo "TestT100String" | grep -o '[0-9]\+'
The method you use to put the results in an array depends somewhat on how the actual data is being retrieved. There's not enough information in your question to be able to guide you well. However, here is one method:
index=0
while read -r line
do
array[index++]=$(echo "$line" | grep -o '[0-9]\+')
done < filename
Here's another way:
array=($(grep -o '[0-9]\+' filename))
Pure Bash. Use parameter substitution (no external processes and pipes):
string="TestT100String"
echo ${string//[^[:digit:]]/}
Removes all non-digits.
I Know this is an old topic but I came her along same searches and found another great possibility apply a regex on a String/Variable using grep:
# Simple
$(echo "TestT100String" | grep -Po "[0-9]{3}")
# More complex using lookaround
$(echo "TestT100String" | grep -Po "(?i)TestT\K[0-9]{3}(?=String)")
With using lookaround capabilities search expressions can be extended for better matching. Where (?i) indicates the Pattern before the searched Pattern (lookahead),
\K indicates the actual search pattern and (?=) contains the pattern after the search (lookbehind).
https://www.regular-expressions.info/lookaround.html
The given example matches the same as the PCRE regex TestT([0-9]{3})String
Use grep. Sed is an editor. If you only want to match a regexp, grep is more than sufficient.
using awk
linux$ echo -E "TestT100String" | awk '{gsub(/[^0-9]/,"")}1'
100
I don't know why nobody ever uses expr: it's portable and easy.
newName()
{
#Get input from function
newNameTXT="$1"
if num=`expr "$newNameTXT" : '[^0-9]*\([0-9]\+\)'`; then
echo "contains $num"
fi
}
Well , the Sed with the s/"pattern1"/"pattern2"/g just replaces globally all the pattern1s to pattern 2.
Besides that, sed while by default print the entire line by default .
I suggest piping the instruction to a cut command and trying to extract the numbers u want :
If u are lookin only to use sed then use TRE:
sed -n 's/.*\(0-9\)\(0-9\)\(0-9\).*/\1,\2,\3/g'.
I dint try and execute the above command so just make sure the syntax is right.
Hope this helped.
using just the bash shell
declare -a array
i=0
while read -r line
do
case "$line" in
*TestT*String* )
while true
do
line=${line#*TestT}
array[$i]=${line%%String*}
line=${line#*String*}
i=$((i+1))
case "$line" in
*TestT*String* ) continue;;
*) break;;
esac
done
esac
done <"file"
echo ${array[#]}