I have to make this command run from my scala code
perl -ne '/pattern/ && print $1 and last' filename
I have tried
val re = """pattern"""
val file = "filename"
val v= (Process(Seq("""perl -ne '/"""+re+"""/ && print $1 and last' """+file))).!!
But some how despite generating the same command required for command line its still not working.It says:
java.io.IOException: Cannot run program "perl -ne '/pattern/ && print $1 and last' file": error=2, No such file or directory.
Can anyone suggest where its going wrong ?
Maybe you need something like this?
val pattern: String = "..." // your pattern
val perlCode = s""" '/$pattern/ && print $$1 and last' """
val v = (Process(Seq("perl", "-ne", perlCode, file))).!!
The issue is Process takes a Sequence of arguments that will be executed. In your case,
perl -ne '/pattern/ && print $1 and last' filename
perl is the first, -ne the second, followed by the perl code /pattern/ && print $1 and last (note that the single quotes ' are not relevant, they are just used to ensure that the string of code is passed as a single argument to perl) and last you have the filename.
The scala.sys.process docs show you pretty much everything. If your file is an java.io.File, try:
val perlCmd = Seq("perl", "-ne", perlCode)
val file = new java.io.File("/tmp/f.txt")
val result = perlCmd #< file !!
Which is the same as
perl -ne '/pattern/ && print $1 and last' < /tmp.txt
Related
The Goal: Read every line, extract information via regex, return it to the bash script
The Problem: When the whole file is a string in the perl code, it work, however if its given line by line via bash, it wont find anything.
The Bash Side:
while IFS= read -r line
do
RESULT=$(perl /mnt/c/LINUX_STUFF/regex.pl $line)
echo $RESULT
done < example.config
The Perl Side:
use strict;
my $str = $ARGV[0];
my $regex = qr/(^\S*) = (\S*)/mp;
if ( $str =~ /$regex/g ) {
print "$2";
}
The example.config:
[ORACLE]
ORACLE_BASE = /u01/oracle
ORACLE_HOME = $ORACLE_BASE/12.1.0.2
ORACLE_SID = asi1
[ORACLE]
[FTP]
FILE1 = $DUMPFILE.dmp
FILE2 = $DUMPFILE.dmp.gz
FILE3 = $DUMPFILE.md5
[FTP]
As you can see here, it should work: https://regex101.com/r/KlCyVE/9
That's because example.config contains spaces within the lines, so the perl script sees just the first word from each line in $ARGV[0].
This should fix it:
use strict;
my $str = join(" ", #ARGV); #THIS
my $regex = qr/(^\S*) = (\S*)/mp;
if ( $str =~ /$regex/g ) {
print "$2";
}
The line below, from you code, reads the first word from the command line and stores it in $str. Your regex expects the complete line
my $str = $ARGV[0];
Change the shell script from this
RESULT=$(perl /mnt/c/LINUX_STUFF/regex.pl $line)
to this, i.e. quoting the line
RESULT=$(perl /mnt/c/LINUX_STUFF/regex.pl "$line")
Suppose I have a file which has these few lines
Hello abc
hii
how are you
Hello abc
If I want to replace the 2nd occurrence of abc by xyz, how can I do?
I want an output like
Hello abc
hii
how are you
Hello xyz
I tried doing perl -pi -e 's/abc/xyz/ if $. == 2' filename. It is not working for me. Can anyone help me with this?
perl -i -pe's/abc/ ++$count == 2 ? "xyz" : "abc" /eg' file
This works even if abc appears more than once per line.
Count the number of time abc appears and subst if equal 2:
perl -i -pe'$found++ if /abc/; s/abc/xyz/ if $found ==2' filename
I have done it as a script. The first argument is the pattern, the second the replacement, the third the number of repetitions and the forth the file, you can also omit the file and insert the data vía stdin.
#!/usr/bin/env perl
use v5.28;
my $patt = shift;
my $rep = shift;
my $nth = shift;
my $reps = 0;
while (<>) {
$reps++ if /$patt/;
s/$patt/$rep/ if (/$patt/ && $reps == $nth);
print $_;
}
Hi I have a requirement where I need to pull text of the form - = from a large log file.
log file consists of data like this:
[accountNumber=0, email=tom.cruise#gmail.com, firstName=Tom, lastName= , message=Hello How are you doing today ?
The output I expect is:
accountNumber=0
email=tom.cruise#gmail.com
firstName=Tom
etc.
Can anyone please help ? Also please explain the solution so that I can extend it to cater to my similar needs.
I wrote a one-liner for this:
perl -nle 's/^\[//; for (split(/,/)){s/(?:^\s+|\s+$)//g; print}' input.txt
I also made another line of input to test with:
Matt#MattPC ~/perl/testing/13
$ cat input.txt
[accountNumber=0, email=tom.cruise#gmail.com, firstName=Tom, lastName= , message=Hello How are you doing today ?
[accountNumber=2, email=john.smith#gmail.com, firstName=John, lastName= , message=What is up with you?
Here is the output:
Matt#MattPC ~/perl/testing/13
$ perl -nle 's/^\[//; for (split(/,/)){s/(?:^\s+|\s+$)//g; print}' input.txt
accountNumber=0
email=tom.cruise#gmail.com
firstName=Tom
lastName=
message=Hello How are you doing today ?
accountNumber=2
email=john.smith#gmail.com
firstName=John
lastName=
message=What is up with you?
Explanation:
Expanded code:
perl -nle '
s/^\[//;
for (split(/,/)){
s/(?:^\s+|\s+$)//g;
print
}'
input.txt
Line by line explanation:
perl -nle calls perl with the command line options -n, -l, and -e. The -n adds a while loop around the program like this:
LINE:
while (<>) {
... # your program goes here
}
The -l adds a newline at the end of every print. And the -e specifies my code which will be in single quotes (').
s/^\[//; removes the first [ if there is one. This searches and replaces on $_ which is equal to the line.
for (split(/,/)){ begins the for loop which will loop through the array returned by split(/,/). The split will split $_ since it was called with just one argument, and it will split on ,. $_ was equal to the line, but inside the for loop, $_ still get set to the element of the array we are on.
s/(?:^\s+|\s+$)//g; this line removes leading and trailing white space.
print will print $_ followed by a newline, which is our string=value.
}' close the for loop and finish the '.
input.txt provide input to the program.
Going off your specific data and desired output, you could try the following:
use strict;
use warnings;
open my $fh, '<', 'file.txt' or die "Can't open file $!";
my $data = do { local $/; <$fh> };
my #matches = $data =~ /(\w+=\S+),/g;
print join "\n", #matches;
Working Demo
Perl One-Liner
Use this:
perl -0777 -ne 'while(m/[^ ,=]+=[^,]*/g){print "$&\n";}' yourfile
Assuming that each line of the log ends with a closing square bracket, you can use this:
#!/usr/bin/perl
use strict;
use warnings;
my $line = '[accountNumber=0, email=tom.cruise#gmail.com, firstName=Tom, lastName= , message=Hello How are you doing today ?]';
while($line =~ /([^][,\s][^],]*?)\s*[],]/g) {
print $1 . "\n";
}
OK, file contents:
asdasd0
**asdasd1**
asdasd2
asdasd3
asdasd4
**asdasd5**
asdasd6
I want to move "^asdasd5" RegEx matched line before "^asdasd1" RegEx matched line:
asdasd0
**asdasd5**
**asdasd1**
asdasd2
asdasd3
asdasd4
asdasd6
Howto?
Thanks
It's not clear what your pattern is - what is constant, and what is changing.
sed "/.*5/d;/.*1/i"$(sed -n '/.*5/p' FILE) FILE
I delete the line containing a 5, and insert that line behind the line containing the 1.
You can't work with -i here, since the file is his own reference.
sed "/.*5/d;/.*1/i"$(sed -n '/.*5/p' FILE) FILE > FILE.tmp
mv FILE.tmp FILE
Here's a way to do it using ex:
ex inputfile <<'EOF'
/^asdasd5
d
/^asdasd1
-
put
wq
EOF
The same thing all on one line:
printf '%s\n' '/^asdasd5' 'd' '/^asdasd1' '-' 'put' 'wq' | ex inputfile
One way using perl:
s/^(asdasd1.*)(^asdasd5(?:\n|$))/$2$1/sm
An example. Content of script.pl:
use warnings;
use strict;
my $data;
## Read all DATA content into $data variable.
do {
$/ = undef;
$data = <DATA>;
};
## Last 's' flag lets '.*' match newlines.
## 'm' flag lets '^' and '$' match at the beginning or end of each line.
$data =~ s/^(asdasd1.*)(^asdasd5(?:\n|$))/$2$1/sm;
print $data;
__DATA__
asdasd0
asdasd1
asdasd2
asdasd3
asdasd4
asdasd5
asdasd6
Run it like:
perl script.pl
With following output:
asdasd0
asdasd5
asdasd1
asdasd2
asdasd3
asdasd4
asdasd6
This might work for you:
sed '/asdasd1/,/asdasd5/{/asdasd5/{G;b};/asdasd1/{h;d};H;d}' file
Since this is line-oriented, you don't really need a regular expression for this. When you see the start line, begin to capture the lines. When you see the ending line, print it, print the captured lines, and then print the rest of the file:
awk -v start=asdasd1 -v end=asdasd5 '
match($0,start) {capture=1}
match($0,end) {print $0 captured; capture=0; next}
capture {captured = captured RS $0; next}
1
'
The easiest way to do this is a simple awk double-pass algorithm:
awk '(NR==FNR) { if ($0 ~ /asdasd5/) t=$0; next }
/asdasd5/ { next }
/asdasd1/ { print t }
1' file file
use sed's command 'i' to insert before pattern.
See http://www.grymoire.com/Unix/Sed.html#uh-41
I am looking for a solution to do this in Perl.
Example:
If my string is:
my $content = 'toto /app/blah titi\nhuh/app/ttt wew';
and my pattern is: /app/something I want to get as output in an array: /app/blah and /app/ttt.
(which is basically what grep -E -o '\/app\/[a-z]*' does)
I can't get it work !
I tried:
my $content = 'toto /app/blah titi\nhuh/app/ttt wew';
$content =~ m/(\/app\/[a-z]*)/;
print "Group: $1 $2\n";
but this only prints: /app/blah (not /app/ttt)
and anyway, I don't know how to put the results in a table:
my (#table) = #_;
the table does not contain anything!
thx
You want to use the /g modifier to make the regular expression return all the matches as a list:
#table = $content =~ m/(\/app\/[a-z]*)/g;
print "Group: #table\n";
Also, #_ does not have anything to do with regular expressions. Rather, it is the list of parameters that was passed to the current subroutine.
I was working on a one liner for some quick bash scripting where Perl would play one part, this worked for me:
$ echo foo000bar000baz | perl -ne 'for(m/(foo)|(baz)/g){ if ($_ ne "") { print "$_\n"}}'
foo
baz
Works with multiline too
$ echo 'foo
> 123
> bar
> 456
> baz ' | perl -ne 'for(m/(foo)|(baz)/g){ if ($_ ne "") { print "$_\n"}}'
foo
baz
Explanation (Forgive and correct my mistakes as I'm not advanced level at Perl):
STDIN piped to perl : Could be anything, like cat $file
m/Regular Expression within parenthesis indicating capture group/g
Make for loop from matches above
Print if match is not "" (empty)