tcsh scripting : regex in if statement - tcsh

what is the correct way to code this perl statment in tcsh shell script
foreach (#array) {
if (/^(pam|pom)/) {
dosomething();
}
}

Here's one way:
#!/bin/tcsh -f
set array = ( foo pam bar pom baz xpam pamx )
alias dosomething echo
foreach elem ($array:q)
if ($elem:q =~ {pam,pom}*) then
dosomething $elem:q
endif
end
Note that the expression on the right side of the =~ operator is a file matching pattern, not a regular expression, so this solution doesn't generalize to all cases. If you need regular expression matching, you can use the expr command:
expr STRING : REGEXP
or, equivalently:
expr match STRING REGEXP

Related

How to use bash function with arguments in make file

I want to use the bash function in the make file. Without argument, it's working, but how I can use it with arguments.
all :
foo () { echo $1} ; foo "hello"
Writing bash code inside Makefile require special handling for all the characters that are special to Make. In particular, '$', which must be escaped (doubled). Also note that ';' is required before '}'.
In general, when writing bash/sh snipplet inside Makefile, ${XYZ} (or $(XYZ)) will refer to MAKE variable, and $$XYZ (or $${XYZ}}) will refer to the sh variable.
all:
foo() { echo $$1 ; } ; foo "hello"

In Perl, best way to insert a char every N chars

I would like to find the best way in Perl to insert a char every N chars in a string.
Suppose I have the following :
my $str = 'ABCDEFGH';
I would like to insert a space every two chars, so that I get:
my $finalstr = 'AB CD EF GH';
The innocent way would be:
my $finalstr;
while ($str =~ s/(..)//) {
$finalstr .= $1.' ';
}
(But the last space does not make me happy.)
Can we do better? Is it possible using a single substitution pattern s///, especially to use that same string $str (and not using $finalstr)?
The next step: do the same but with text before and after patterns to be cut (and to be kept, for sure), say for example '<<' and '>>':
my $str = 'blah <<ABCDEFGH>> blah';
my $finalstr1 = 'blah <<AB CD EF GH>> blah';
my $finalstr2 = 'blah << AB CD EF GH >> blah'; # alternate
Using positive lookahead and lookbehind assertions to insert a space:
my $str = 'ABCDEFGH';
$str =~ s/..\K(?=.)/ /sg;
use Data::Dump;
dd $str;
Outputs:
"AB CD EF GH"
Enhancement for limiting the Translation
If you want to apply this modification to only part of the string, break it into steps:
my $str = 'blah <<ABCDEFGH>> blah';
$str =~ s{<<\K(.*?)(?=>>)}{$1 =~ s/..\K(?=.)/ /sgr}esg;
use Data::Dump;
dd $str;
Outputs:
"blah <<AB CD EF GH>> blah"
The best solution using substitutions would probably be s/\G..\K/ /sg. Why?
The \G anchores at the current “position” of the string. This position is where the last match ended (usually this is set to the beginning of the string. If in doubt, set pos($str) = 0). Because we use the /g modifier, this will be where the previous substitution ended.
The .. matches any two characters. Note that we also use the /s modifier which causes . to really match any character, and not just the [^\n] character class.
The \K treats the previous part of the regex as a look-behind, by not including the previously matched part of the string in the substring that will be substituted. So \G..\K matches the zero length string after two arbitrary characters.
We substitute that zero length string with a single space.
I'd let the regex engine handle the substitution, rather than manually appending $1 . " ". Also, my lookbehind solution avoids the cost of using captures like $1.
You want the //g modifier with its many capabilities. See e.g. here for an introduction to the intricacies of global matching.
Do you mean something like...
$str =~ s/(..)/$1 /sg;
update: For more complex substitutions as the one you are asking in the second part of your question, you can use the e modifier that allows you to evaluate arbitrary perl code:
sub insert_spcs {
my $str = shift;
join ' ', $str =~ /(..?)/sg
}
my $str = 'blah <<ABCDEFGH>> blah';
$str =~ s/<<(.*?)>>/'<< '.insert_spcs($1).' >>'/se;
Personally I'd split the text with m//g and use join:
my $input = "ABCDEFGH";
my $result = join " ", ( $input =~ m/(..)/g );
say "RESULT <$result>";'
Yields
RESULT <AB CD EF GH>
The other answers are better, but just for giggles:
join ' ', grep length, split /(..)/, 'ABCDEFGH';

parameter expansion with substitution in bash

I have a trivial problem with regular expression in bash.
#!/bin/bash
FNAME=$1
echo ${FNAME//.*\/tests\//}
I want to remove everything before /test/ including the /test/ as well. Because of some reasons ".*" doesn't work.
$ ./eclipse/unittest.sh /foo/tests/bar
/foo/tests/bar
How do I select anything in bash reg exp?
You can use # followed by a pattern to remove everything up to and including the pattern. It will use the shortest match:
function f {
echo ${1#*/tests/}
}
$ f /foo/tests/bar
bar
$ f /foo/tests/bar/tests/last
bar/tests/last
If you want to use the longest match, you can use ##:
function f {
echo ${1##*/tests/}
}
$ f /foo/tests/bar
bar
$ f /foo/tests/bar/tests/last
last

Shell script to manipulate if loop

I am trying to modify a if loop in a large code base.My need is as follows.
The code may contain as follows.This is just a random combination example of an if condition.I need to modify if else if conditions alone.
if((A==B)&&(C==D)&&((E==F)||(G==H))||(I)&&(J!=K))
should be modified as
if((string.Compare(A,B)==0)&&(string.Compare(C,D)==0)&&((string.Compare(E,F)==0)||(string.Compare(G,H)==0))||(I)&&(string.Compare(J,K)!=0))
I tried with Java but utterly failed.I believe this is possible with sed or awk.Any help?
You could do it basically with any language that supports regular expressions replacement.
Here's a 3 lines working C# example:
string text = "if((A==B)&&(C==D)&&((E==F)||(G==H))||(I)&&(J!=K))";
string pattern = #"\((?:(\w)((?:=|!)=)(\w))\)";
var replaced = Regex.Replace(text, pattern, m => string.Format("(string.Compare({0},{1}){2}0)", m.Groups[1].Value, m.Groups[3].Value, m.Groups[2].Value));
Console.WriteLine(replaced);
And the result:
if((string.Compare(A,B)==0)&&(string.Compare(C,D)==0)&&((string.Compare(E,F)==0)||(string.Compare(G,H)==0))||(I)&&(string.Compare(J,K)!=0))
sed -r 's/([[:alpha:]])([=!]=)([[:alpha:]])/string.Compare(\1,\3) \2 0/g'
The spaces around \2 aren't strictly necessary.
Basically you don't need to use awk or sed to construct the if statement. It is enough to write:
if [ A == B -a C == D -a ( E == F -o G == H ) -o I -a J != K ]; then
your code here
fi
The == operator compares strings. If you wanted to compare numbers use -eq operator. See this chapter of bash manual (scroll down to test command), and the description of usage of primary conditional expressions

How can I escape an arbitrary string for use as a command line argument in Windows?

I have a list of strings and I want to pass those strings as arguments in a single Windows command line call. For simple alphanumeric strings it suffices to just pass them verbatim:
> script.pl foo bar baz yes no
foo
bar
baz
yes
no
I understand that if an argument contains spaces or double-quotes, I need to backslash-escape the double-quotes and backslashes, and then double-quote the argument.
> script.pl foo bar baz "\"yes\"\\\"no\""
foo
bar
baz
"yes"\"no"
But when I try to pass an argument with literal percent signs, this happens:
> script.pl %PATH%
C:\Program
Files\PHP\;C:\spaceless\perl\bin\;C:\Program
Files\IBM\Java60\bin;
(...etc.)
Double quoting doesn't work:
> script.pl "%PATH%"
C:\Program Files\PHP\;C:\spaceless\perl\bin\;C:\Program Files\IBM\Java60\bin; (...etc.)
Nor does backslash-escaping (notice how the backslashes are present in the output):
> script.pl \%PATH\%
\%PATH\%
Also, the rules are inconsistent for backslash-escaping backslashes:
> script.pl "\\yes\\"
\\yes\
> script.pl "\yes\\"
\yes\
> script.pl "\yes\"
\yes"
Also, doubtless there are special characters in the Windows command line shell, much like there are in all shells. What, then, is the general procedure for safely escaping arbitrary command line arguments for use at the Windows command line?
The ideal answer will describe a function escape() which can be used in situations like the following (a Perl example):
$cmd = join " ", map { escape($_); } #args;
Here are some more example strings which should be safely escaped by this function (I know some of these look Unix-like, that's deliberate):
yes
no
child.exe
argument 1
Hello, world
Hello"world
\some\path with\spaces
C:\Program Files\
she said, "you had me at hello"
argument"2
\some\directory with\spaces\
"
\
\\
\\\
\\\\
\\\\\
"\
"\T
"\\T
!1
!A
"!\/'"
"Jeff's!"
$PATH
%PATH%
&
<>|&^
()%!^"<>&|
>\\.\nul
malicious argument"&whoami
*#$$A$##?-_
Here is an msdn blogpost showing how. It however assumes that every command line program internally uses CommandLineToArgvW to parse it's command line (not a shabby assumption, since it's part of the Shell32 library).
Original link (may not work): http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx
Web archive link: https://web.archive.org/web/20190109172835/https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
To escape a command line argument, use the following:
sub escapeArg {
my $arg = shift;
# Sequence of backslashes followed by a double quote:
# double up all the backslashes and escape the double quote
$arg =~ s/(\\*)"/$1$1\\"/g;
# Sequence of backslashes followed by the end of the arg,
# which will become a double quote later:
# double up all the backslashes
$arg =~ s/(\\*)$/$1$1/;
# All other backslashes do not need modifying
# Double-quote the whole thing
$arg = "\"".$arg."\"";
# Escape shell metacharacters
$arg =~ s/([()%!^"<>&|;, ])/\^$1/g;
return $arg;
}
To escape the actual command line command, for example when invoking a command with a ridiculous name such as ()!&%PATH%^;, .exe (which is perfectly legal), use the following:
sub escapeCmd {
my $arg = shift;
# Escape shell metacharacters
$arg =~ s/([()%!^"<>&|;, ])/\^$1/g;
return $arg;
}
Note that using escapeArg() for the command will not work.
Sources:
http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx
http://support.microsoft.com/kb/103368

Resources