How can I capture group from string using regexp in shell in msysgit on Windows? - regex

[Editor's note: The OP has later clarified that he's running bash as part of msysgit, the Git version for Windows.]
I'm trying to get last digits from the string. I have a little script but it doesn't work and i don't know why:
#!bin/bash
TAGS="MASTER_46"
re="_(\d+)"
if [[ ${TAGS}=~$re ]]; then
echo "Find"
echo ${BASH_REMATCH}
echo ${BASH_REMATCH[1]}
fi
The output:
Find
{empty}
{empty}
I am using bash
$ bash --version
GNU bash, version 3.1.20(4)-release

There are several problems:
bash doesn't support \d. Use [0-9].
Whitespace is needed around the operator: $TAGS =~ $re, otherwise bash parses it as [[ -n "$TAGS=~$re" ]].
Path to the shell is /bin/bash, not bin/bash.

Update, based on the OP's clarification re environment and his own findings:
tl;dr:
msysgit (as of version 1.9.5) comes with a bash executable that is compiled without support for =~, the regex-matching operator
A limited workaround is to use utilities such as grep, sed, and awk instead.
To solve this problem fundamentally, install a separate Unix emulation environment such as MSYS or Cygwin, and use git.exe (the core of msysgit) from there.
choroba's answer has great pointers, but let me add that, since you get the following error message:
conditional binary operator expected syntax error near =~
the implication is either that
your bash version is too old to support =~, the regex-matching operator.
your bash version was compiled without regex support
Given that =~ was introduced in bash 3.0 (see http://tiswww.case.edu/php/chet/bash/NEWS) and you're running 3.1.x, it must be the latter, which indeed turned out to be true:
The OP runs msysgit, the official Git version for Windows that comes with bash and a set of Unix utilities.
As it turns out, as of version 1.9.5, the bash executable that comes with msysgit is built without regex support, presumably due to technical difficulties - see https://groups.google.com/forum/#!topic/msysgit/yPh85MPDyfE.
Incredibly, the "Known Issues" section of the release notes does not mention this limitation.
Your best bet is to:
Install MSYS to use as your Unix emulation environment - its bash does come with =~ support (note that msysgit was originally forked from MSYS).
Alternatively, to get better Unix emulation and more tools at the expense of a larger installation footprint and possibly performance, install Cygwin instead.
In MSYS, use only git.exe from msysgit, via the Windows %PATH%.
To that end, be sure to install msysgit with the Run Git from the Windows Command Prompt option - see https://stackoverflow.com/a/5890222/45375
Alternatively, add C:\Program Files\Git\cmd (assumes the default path on 32-bit Windows, on 64-bit Windows it's C:\Program Files (x86)\Git\cmd) manually to your Windows %PATH%, OR extend $PATH in your MSYS ~/.profile file (e.g., PATH="$PATH:/c/program files/git/cmd").
You could hack your msysgit installation, but it hardly seems worth it and I don't know what the side effects are;
If you really wanted to try, do the following: Copy the following files from an MSYS installation's bin directory to msysgit's bin directory: bash.exe, sh.exe, msys-termcap-0.dll - in other words: replace msysgit's bash altogether.

Related

Unable to use sed command in Windows Command Prompt due to 'unterminated address regex'

I'm trying to run a sed command on a Windows machine from the command prompt (CMD.exe) but I am struggling to understand the regular expression and how to escape the string properly when running on Windows. Ideally, I want to develop a solution that works across UNIX and Windows.
sed is not available on Windows so I have installed it via the gnuWin32 project which works well.
The unix format for the command is:
sed -i '' -e 's/\\/_next/\\.\\/next/g' out/**.html
Through a process of trial an error I have managed to get this far:
sed -i \'\' -e \'s/\\/_next/\\.\\/next/g\' out/**.html
but I get an error:
sed: -e expression #1, char 27: unterminated address regex
So there's definitely something wrong with my regex, probably the escaping of various parts?
Any ideas how I might go about fixing this?
Update:
I'm getting the code from here where unfortunately only Linux and OSX are covered.
You need to use
sed -i "s/\\/_next/\\.\\/next/g" out/**.html
The Windows GNU sed does not require the '' empty argument after -i option, they can be safely removed.
Also, the sed command in Windows console should be used in double quotes.

Multi-line regular expression issue in Perl on Windows 10.

I'm trying to convert this pattern in files
Insert 18333fig0101.png
Figure 1-1. Local version control diagram.
to
![Figure 1-1. Local version control diagram.](../figures/18333fig0101-tn.png)
This is the perl command:
perl -i -0pe 's/^Insert\s*(.*)\.png\s*\n([^\n]*)$/!\[\2](..\/figures\/\1-tn.png)/mg' */*.markdown
This works fine on Mac OS X, but it doesn't work on Windows 10.
I installed perl using pacman -S perl from MSYS2.
This is also not a \r\n issue as I checked there is no \r in the document.
Is this a known issue on Windows? Or, is there something different option needed for Windows?
When I run the same command (after changing single quotes to double quotes), I get the following error message:
Can't do inplace edit without backup.
This is documented in perldiag:
You're on a system such as MS-DOS that gets confused if you try
reading from a deleted (but still opened) file. You have to say -i.bak, or some such.
When I change the command to perl -i.bak ..., it works.

Are negative lookbehind in regex searches possible in Geany?

Geany's documentation on negative assertions makes it look like they're possible.
For reference, this works and gives me results:
pcregrep -r "(?<!= )function\(" src/main-js/
But the same regex, or any regex with a negative lookbehind, gives me no result when launched from Geany (v 1.24.1)
Where is the problem? Is the documentation wrong?
Precision: the topic isn't about how to avoid doing a negative look behind, but about how to do any standard PCRE negative look behind.
I got support from the Geany developers on Freenode, and it was very helpful. Here is what they told me:
The documented RE syntax only applies to the RE engine directly used by
Geany (e.g. in Find), but the Find in Files features calls the grep tool
(as configured in preferences->tools->grep), which has its own syntax.
For GNU grep, you can add "-P" to the "Extra options" field in the
dialog
However, after you tried it, you had this error:
/bin/grep: conflicting matchers specified
... to which I was told this was a Geany bug. Geany calls grep -E, and -P is not compatible with it.
Your only workaround is to have a shell script calling grep with -P instead of -E, and use this script. You should be able to configure the grep tool to call in Geany preferences.
An example of said shell script:
#!/bin/sh
matchopts=$(echo "$1" | tr E P)
shift
exec grep $matchopts "$#"
Geany uses either -F or -E (these are the only available engines in POSIX grep) for grep, hence why you can't pass -P.
I've reported the bug to the Geany developers.
Another workaround is to avoid the negative lookbehind assertion… but it's a lot uglier:
(^.?|[^=] |=[^ ]|[^=][^ ])function

Duplicate Perl installation on CENTOs 64 bit

I insatlled perl on my machine and on giving follows command
perl -e 'print("#INC\n");'
I get this output
/usr/local/lib/perl5/site_perl/5.18.1/x86_64-linux /usr/local/lib/perl5/site_perl/5.18.1
/usr/local/lib/perl5/5.18.1/x86_64-linux /usr/local/lib/perl5/5.18.1 .
But the MACHINE that is working properly gives follows output for the
same command
/usr/local/lib64/perl5 /usr/local/share/perl5/usr/lib64/perl5/vendor_perl
/usr/share/perl5/vendor_perl/usr/lib64/perl5 /usr/share/perl5 .
YOU CAN SEE THE DIFF INT PATH for lib & lib64
How can i correct the above ??
please help
Perl comes pre-installed on every Linux machine - maybe the machine that is working properly uses the stock perl. You can identify the location of the perl executable issuing which perl in the command line.
Also, you can check the perl version by running perl -v - if the perl on the machine that is working is older, it might be the OS perl.
Regarding the ways to manipulate the lib path, have a look at the tutorial that Gabor Szabo wrote regarding How to change #INC to find Perl modules in non-standard locations

Mac OSX and Unix quick questions

I have 3 questions. I am making a C++ executable to launch a Perl program I made. I will compile it for Winows, Mac OSX and Linux. It's pretty much just: system("perl progam.pl");
When compiled with Mac OSX, the program starts in ~. How would I get it to start in the dir it was launched from, or is it just a problem with the compiler?
I'm using - echo -n -e "\033[0;Program\007" - in an attempt to make the windows title "Program". Is this is best way?
I'm using - echo -n -e "\033[7;30;47m" - to make the background of the window black. Is this the best way?
Thanks.
This sounds like something Finder is doing. Launching the app from a shell should work as you expect.
Use tput
See answer to 2, above.
On Mac OS/Unix, invoking system does not change the current working dir. When executing program.pl the current working directory is the same from which you executed the C++ executable. When you launch the executable using Launch Services (e.g. the Finder) the working directory should be /.
On #1 you can refer to the current directory with ./ so system("perl ./progam.pl"); should do it assuming both scripts are sitting in the same folder. ../program.pl would be one level higher.
For #1, use getcwd & then pass an explicit path to system:
cwd=getcwd(NULL, PATH_MAX);
sprintf(cmd, "perl %s/program.pl", cwd);
system(cmd);
free(cwd);
If your perl program itself relies on a specific working directory, then do this instead:
sprintf(cmd, "cd %s && perl program.pl", cwd);
This is probably a silly question, but why are you making an application to launch a perl script? Just add the following to the top of your perl script and use "chmod a+x" to make it executable:
#! /usr/bin/perl
When you use the system command from C and C++, you are basically launching the default system shell and executing the given command in that shell. Doing that is not very portable and somewhat defeats the purpose of using C or C++ (since you could simply create a shell script that does the same thing). If you want to actually do this with C++, you should probably use popen or fork+exec to launch perl. Generally speaking, it isn't nice to end users to play with their Terminal in the manner that you have proposed; most users, by default, have the Terminal configured to display the most recently executed command or their current directory or some other information of their choosing, and changing that is -- on UNIX systems such as Mac OS X and Linux -- considered improper etiquitte. If you are trying to create a terminal interface, though, you might want to look at the curses library.