Store regex pattern in a variable in bash script - regex

I have the following bash script code:
GOAL="${1:-help}"
TARGET="${2}"
MODULES_LIST="app|tester"
echo "-> Running $TARGET..."
MODULES_LIST_PATTERN = "^($MODULES_LIST)$"
if [[ "$TARGET" =~ $MODULES_LIST_PATTERN ]]; then
run_${TARGET}
else
print_error "You must include an existing module: {$MODULES_LIST}"
exit 1
fi
As you can see, I have a MODULES_LIST variable where I store the modules supported by the application, then I create a regex pattern MODULES_LIST_PATTERN containing the value of the previous var, and use it to check if the provided parameter matches any of the modules. However, it is not working as expected, since when I run ./myscript.sh run app it prints ERROR] You must include an existing module: {app|tester}.
Could someone tell me the proper way of doing this?

My fault... the problem is MODULES_LIST_PATTERN = "^($MODULES_LIST)$", you can't have whitespaces surrounding the equals sign. After fixing that, it works as expected.

Related

Extracting group from regex in shell script using grep

I want to extract the output of a command run through shell script in a variable but I am not able to do it. I am using grep command for the same. Please help me in getting the desired output in a variable.
x=$(pwd)
pw=$(grep '\(.*\)/bin' $x)
echo "extracted is:"
echo $pw
The output of the pwd command is /opt/abc/bin/ and I want only /root/abc part of it. Thanks in advance.
Use dirname to get the path and not the last segment of the path.
You can use:
x=$(pwd)
pw=`dirname $x`
echo $pw
Or simply:
pw=`dirname $(pwd)`
echo $pw
All of what you're doing can be done in a single echo:
echo "${PWD%/*}"
$PWD variable represents current directory and %/* removes last / and part after last /.
For your case it will output: /root/abc
The second (and any subsequent) argument to grep is the name of a file to search, not a string to perform matching against.
Furthermore, grep prints the matching line or (with -o) the matching string, not whatever the parentheses captured. For that, you want a different tool.
Minimally fixing your code would be
x=$(pwd)
pw=$(printf '%s\n' "$x" | sed 's%\(.*\)/bin.*%\1%')
(If you only care about Bash, not other shells, you could do sed ... <<<"$x" without the explicit pipe; the syntax is also somewhat more satisfying.)
But of course, the shell has basic string manipulation functions built in.
pw=${x%/bin*}

Powershell: Read a section of a file into a variable

I'm trying to create a kind of a polyglot script. It's not a true polyglot because it actually requires multiple languages to perform, although it can be "bootstrapped" by either Shell or Batch. I've got this part down no problem.
The part I'm having trouble with is a bit of embedded Powershell code, which needs to be able to load the current file into memory and extract a certain section that is written in yet another language, store it in a variable, and finally pass it into an interpreter. I have an XML-like tagging system that I'm using to mark sections of the file in a way that will hopefully not conflict with any of the other languages. The markers look like this:
lang_a_code
# <{LANGB}>
... code in language B ...
... code in language B ...
... code in language B ...
# <{/LANGB}>
lang_c_code
The #'s are comment markers, but the comment markers can be different things depending on the language of the section.
The problem I have is that I can't seem to find a way to isolate just that section of the file. I can load the entire file into memory, but I can't get the stuff between the tags out. Here is my current code:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
powershell -ExecutionPolicy unrestricted -Command ^
$re = '(?m)^<{LANGB}^>(.*)^<{/LANGB}^>';^
$lang_b_code = ([IO.File]::ReadAllText(^'%0^') -replace $re,'$1');^
echo "${re}";^
echo "Contents: ${lang_b_code}";
Everything I've tried so far results in the entire file being output in the Contents rather than just the code between the markers. I've tried different methods of escaping the symbols used in the markers, but it always results in the same thing.
NOTE: The use of the ^ is required because the top-level interpreter is Batch, which hangs up on the angle brackets and other random things.
Since there is just one block, you can use the regex
$re = '(?s)^<{LANGB}^>(.*)^^.*^<{/LANGB}^>';^
but with -match operator, and then access the text using $matches[1] variable that is set as a result of -match.
So, after the regex declaration, use
[IO.File]::ReadAllText(^'%0^') -match $re;^
echo $matches[1];

Detecting errors of a command that print nothing if the command was successful using Perl and Expect

I am trying to automate the configuration of a server using perl and the expect module. I have been using the expect module three days but now I have encountered a problem that I can't solve.
My problem is when im executing a command that prints no output if it is successful but prints an error message if something went wrong. An example of such command is the cd command:
$ cd .
$
$ cd sadjksajdlaskd
sadjksajdlaskd: No such file or directory.
$
What I would like to do is to send the command to the server, and then perform an expect call to check if something other than the prompt sign was printed. Something like this:
$com->send("cd $dir");
$com->expect(2,
["^[^$#]*", sub {
my $self = shift;
my $error = $self->match();
die "ERROR: $error";
}],
"-re", "^[$#]"
);
The problem I have is that when I perform the expect call it will match against all previous text and not against text received after the send call, so it will always match and report an error. How do I make expect match only agains the text received after the send call? Is it possible to clear the buffer of the expect module or is it possible to achieve this kind of error detection some other way?
I also wonder how the expect module handles regular expressions. If I for example use "^[$#]\$" as the regular expression to match the prompt of the terminal, will the \$ part of the regular expression match end of line or an actual dollar sign? If i remove the \ perl complains.
Thanks in advance!
/Haso
EDIT: I have found a solution:
The solution was to use $com->clear_accum() which clears the accumelator. I have tried using it before but it seems like this function only works at random, or maybe I don't understand what clear_accum() is suppose to do.
EDIT: A final note about clear_accum():
The reason the clear_accum() function seems to work at random is because the text generated from the previous send is not read into the accumelator until an expect() call is made. So in order to truly clear all previous data is to first perform an expect() call and then clear the accumelator:
#To clear all previous data
$com->expect(0);
$com->clear_accum();
akarageo#Pal4op:~> cd banana
bash: cd: banana: No such file or directory
akarageo#Pal4op:~:( > echo $?
1
i.e. check the error code that CD returns, 0 means OK anything else is an error, No need to check the prompt , and btw, the CD command does not generate the prompt the shell does, so that must be part of your confusion also.
try $object->exitstatus() if it is of any help

Bash script - Need help getting match and substitution working

I am trying to get parameter substitution working in my bash script ... I know I have gotten this all wrong ... I am trying to create a script that will rename a PART of a file.
#!/bin/bash
for i in *.hpp; do mv -v "$3 ${$3/$1/$2}" ; done
The error I am getting is:
line 2: $3 ${$3/$1/$2}: bad substitution
${$3} will attempt to interpolate ${"CONTENTS OF $3"} into a variable. It is more likely that you want ${3}. It is even more likely that you want ${i}.

Conditional statement using rexep with bash

I want to use the "conditional regexp" structure from bash, present since the third version of bash (circa 2004).
It's supposed to go like this:
if [[ $string =~ $regexp ]]; then
#do smthg
else
#do somthg else
fi
So here's my code, following this structure, and its role is to check if the name contained in SSID is presend in the output from iw dev wlan0 link :
if [[ $(iw dev wlan0 link) =~ $SSID+ ]]; then
#do sthming
else
echo "wrong network"
fi
For some reason that i can't decipher, this statement works pretty well if I run it right into the bash shell, like
if [[ $(iw dev wlan0 link) =~ $SSID+ ]]; then echo found; else echo not found; fi
But if i run it inside the script its contained, it'll spit out:
scripts/ssidchecker.sh: 22: [[: not found
22 being the line of the "fi" keyword. The strangest thing is that it will always execute the code contained in the "else" statement
Is "not found" meant to indicate me that the regexp dind't find anything in that string? Is it a real error message?
Starting Note: Answer created with input from comments in question, especially in response of the last comment.
First, what is [[? It is a shell keyword.
samveen#maverick:~$ type [[
[[ is a shell keyword
This means that [[ is an internal keyword of bash, not a command and thus will not work with other shells. Thus, your error output
scripts/ssidchecker.sh: 22: [[: not found
means that the shell you're using is probably
Not bash
A version of bash older than 2.02 ([[ introduced in Bash-2.02)
Given that 2.02 is a really really old version (pre Y2K), all this just points to the fact that the shell you're using to run the script is probably not /bin/bash, instead probably being /bin/sh which is the most common path used for Bourne shell scripts shebang (the #!) line.
Please change that to /bin/bash or explicitly run bash scripts/ssidchecker.sh and you're good to go.
As to why the else section was always executed, the [[ command not being found is the same as a failure (non-zero return value), from the viewpoint of if. Thus the else section is executed.
samveen#maverick:~$ /bin/whosyourdaddy
-bash: /bin/whosyourdaddy: No such file or directory
samveen#maverick:~$ echo $?
127
As a side note on portability, the bash hackers wiki also says the following about the [[ keyword:
Amongst the major "POSIX-shell superset languages" (for lack of a
better term) which do have [[, the test expression compound command is
one of the very most portable non-POSIX features. Aside from the =~
operator, almost every major feature is consistent between Ksh88,
Ksh93, mksh, Zsh, and Bash. Ksh93 also adds a large number of unique
pattern matching features not supported by other shells including
support for several different regex dialects, which are invoked using
a different syntax from Bash's =~, though =~ is still supported by ksh
and defaults to ERE.
Thus your script will probably fail on the =~ even if the shell supports [[, in case the shell isn't bash but supports [[.