Regex and if in shell script - regex

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

Related

Why does BASH_REMATCH return empty when the script file is sourced from zsh?

So I created myself a cute little bash script:
#!/usr/bin/env bash
TEXT="FOO BAR"
REGEX="FOO (.+)"
if [[ $TEXT =~ $REGEX ]]; then
echo "Matched ${BASH_REMATCH[1]}"
else
echo "No match."
fi
Pretty basic. If I run ./cutescript.sh, then I get the result:
Matched BAR
But if I source the script, . ./cutescript.sh, then it still matches, but BASH_REMATCH[1 is empty.
Wat.
I'm on MacOS Catalina 10.15.7 (19H2), executing this in zsh, but with the bash shebang.
Can anyone explain this irregularity?
When you read the file with ., it gets executed by whatever shell you're running - in this case, you said you're in zsh. The name of the BASH_REMATCH array is, as the name implies, specific to bash; if your shell is zsh, for example, then the matched text in this case would be found in $match[1] instead. And I don't think ksh does true regex matching at all.
Now, armed with the knowledge that BASH_REMATCH doesn't exist natively in zsh, I did a little more digging:
This post is actually a duplicate. There's another question here that explains the solution: BASH_REMATCH doesn't capture
Setting options KSH_ARRAYS BASH_REMATCH allows zsh to emulate bash's regular expression features.
A simple way to make the above script compatible with zsh is:
#!/usr/bin/env bash
# Ensures that BASH_REMATCH works if called in zsh.
setopt KSH_ARRAYS BASH_REMATCH
TEXT="FOO BAR"
REGEX="FOO (.+)"
if [[ $TEXT =~ $REGEX ]]; then
echo "Matched ${BASH_REMATCH[1]}"
else
echo "No match."
fi
unsetopt KSH_ARRAYS BASH_REMATCH
Also another related question: What is the zsh equivalent for $BASH_REMATCH[]?

Why do git commit-msg on Windows not match regex

I am trying to create a git commit-msg hook, which includes a simple regex to verify the log message. It is not working using the usual bash syntax.
I tried it using a very simple regex, and it is still not working
Any idea what I might be doing wrong?
Here is a simple example including an obvious match, but it is printing out "no match"
#!/bin/bash
message="[GLSD-0000]"
echo "Message: '$message'"
regex="\[GLSD-\w+\]"
if [[ $message =~ $regex ]]; then echo "yes";else echo "no match!"; fi
Using git version 2.18.0.windows.1
A few things to note from you attempt made,
Your interpreter does #!/bin/sh does not support the regex operation in bash, even-though you have not used it. You should be using the bourne again shell bash (#!/usr/bin/env bash).
The [[..]] with an = does a string match on left side operand with the right side operand. For regular expression support, you need to use the ~ operator
The bash only supports a minimal version of ERE (Extended Regular expression) in which \w (all words) is not supported.
So in a script targeted for a bash shell, you should be writing it as
#!/usr/bin/env bash
# equivalent of '\w' in the regex flavor supported by bash
re='\[GLSD-[A-Za-z0-9_]+\]'
msg='[GLSD-0000]'
[[ $msg =~ $re ]] && echo "yes" || echo "no match!"

Changing the bash =~ operator to a sh compatible argument

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.

can i use regex in a bash shell script

I am a first year Computer technician student, and before now have never actually used linux. I grasped the basics of scripting fairly quickly and am trying to write a script that will create a directory and a soft link for each assignment. seeing as we average two assignments a week i thought this would be helpful.
I am having trouble making my script accept only numbers as variables. I have it mostly working (mostly) with use of 3 case statements, but would rather use basic regex with an if statement, if I can.
if [ $# != 1 ]; then
red='\033[0;31m'
NC='\033[0m'
blue='\033[1;34m'
NC='\033[0m'
echo 1>&2 "${blue}ERROR:${NC} $0 :${red}expecting only one variable, you gave $#($*)${NC}"
echo 1>&2 "${blue}Usage:${NC} $0 :${red}number of assignment.${NC}"
exit 2
fi
case $1 in
[[:punct:]]*) echo 1>&2 "Numeric Values Only"
exit 2
;;
[[:alpha:]]*) echo 1>&2 "Numeric Values Only"
exit 2
;;
[[:space:]]*) echo 1>&2 "Numeric Values Only"
exit 2
;;
esac
the script then makes the directory and creates a soft link for the marking script (if its posted), and ends. can anyone help me shorten/eliminate the case statements
You cannot use regular expressions in portable shell scripts (ones that will run on any POSIX compliant shell). In general, patterns in the shell are globs, not regular expressions.
That said, there are a few other options. If you are using Bash specifically, you have two choices; you can use extended globs, which give you some regex like functionality:
shopt -s extglob
case $1 in
+([[:digit:]]) ) echo "digits" ;;
*) echo "not digits" ;;
esac
Another option is that Bash has the =~ operator in the [[ ]] conditional construct to match strings against a regex; this doesn't work in a case statement, but works in an if:
if [[ $1 =~ [0-9]+ ]]
then
echo "digits"
fi
Finally, if you want to do regular expression matching portably (so it will run in other POSIX shells like ash, dash, ksh, zsh, etc), you can call out to grep; if you pass -q, it will be silent about the matches but return success or failure depending on whether the input matched:
if echo "$1" | grep -qE "[0-9]+"
then
echo "digits"
fi

Regular expression does not match, no idea why

I moved my server to a new one (cheaper). Both have the same Linux (CentOS) in different versions (5.0 and 6.5). I have a shell script that filters a line out of a log:
if [ -f $URLFILE ]
then
echo "File found, getting userinfo..."
while read line;
do
if [[ $line =~ ".Userlist: .*" ]]
then
echo "Found user information."
echo $line > /home/....net.txt;
...
So, if the red line matches the regex, it should be echoed into the file. This works fine on the old system but the regex does not match on the new system (without any other changes). The regex is correct as far as a regex tester on the Internet tells me.
There are 2 problems:
sh doesn't support regex matching using =~ like bash
Regex should NOT be quoted and your variable should preferably be quoted.
You can use this in BASH:
if [[ "$line" =~ Userlist:[[:blank:]] ]]
OR just avoid using regex altogether and use glob matching:
if [[ "$line" == *"Userlist: "* ]]