Using pipe when executing command in perl - perl

I am trying to use following command in perl but it giving me error
system("zcat myfile.gz | wc > abc.txt");
But when i run this I am getting error
syntax error near unexpected token `|'
Even if I remove >abc.txt I am still getting error.
Can we use pipe with system command?
Here are error details:
sh: -c: line 1: syntax error near unexpected token `|'
sh: -c: line 1: ` | wc '

Next time, test your demo program to make sure it actually exhibits the behaviour you said it does. You actually ran something closer to
while (my $file_name = <>) {
system("zcat $file_name | wc > abc.txt");
}
There are two errors in that:
You didn't remove the trailing newline, so the shell was trying to execute
zcat def.gz
| wc >abc.txt
instead of
zcat def.gz | wc >abc.txt
You didn't transform the file name into a shell literal before emdedding it your command.
Consider what would happen if the file name contained a space. You would be executing
zcat def ghi.gz | wc >abc.txt
instead of
zcat 'def ghi.gz' | wc >abc.txt
Solution:
use String::ShellQuote qw( shell_quote );
while (my $file_name = <>) {
chomp($file_name);
system("zcat -- ".shell_quote($file_name)." | wc > abc.txt");
}

It is working as expected:
perl -lne 'system("cat *.java|wc");'
Something odd with your filename, maybe.
You could check the interpolation of your shell like this:
my #file = `ls -1 myfile*.gz`;chomp(#files);
print join("\n",#files);
There are other possibilites to execute in perl, like backtick, open with |, qx.
If you are trouble with filenames, you could get the filenames by yourself and call the system in a specific way to avoid executing shell: http://docstore.mik.ua/orelly/perl/cookbook/ch19_07.htm
If there is only one scalar argument, the argument is checked for shell metacharacters, and if there are any, the entire argument is passed to the system's command shell for parsing (this is /bin/sh -c on Unix platforms, but varies on other platforms). If there are no shell metacharacters in the argument, it is split into words and passed directly to execvp , which is more efficient.

I got this error message when trying to use backticks to execute a pipeline that included a cut -d \| command. Turns out I had to double escape the pipe character eg cut -d \\|

Related

How to remove carriage return in Perl properly?

I have a code that looks like this
sub ConvertDosToUnix{
my $file = shift;
open my $dosFile, '>', $file or die "\nERROR: Cannot open $file";
select $dosFile;
print("Converting Dos To Unix");
`perl -p -i -e "s/\r//g" $dosFile`;
close $dosFile;
}
Also, the perl command works when I used that outside the subroutine or in the main function. But when I created a separate subroutine for converting dos to unix, I got an error that says:
sh: -c: line 0: syntax error near unexpected token `('
//g" GLOB(0x148b990)' -p -i -e "s/
In which I don't understand.
Also, I also tried dos2unix but for some reason, it doesn't totally remove all the carriage returns like the perl command.
Honestly, you seem a little confused.
The code you have inside backticks is a command that is run by the shell. It needs to be passed a filename. You have your filename in the variable $file, but you pass it the variable $dosFile which contains a file handle (which stringifies to "GLOB(0x148b990)" - hence your error message).
So all your work opening the file is wasted. Really, all you wanted was:
`perl -p -i -e "s/\r//g" $file`
But your system almost certainly has dos2unix installed.
`dos2unix $file`
I should also point out that using backticks is only necessary if you want to capture the output from the command. If, as in this case, you don't need the output, then you should use system() instead.
system('dos2unix', $file);

Executing shell command with pipe in perl

I want the output of the shell command captured in variable of a perl script, only the first section of the command before the pipe "|" is getting executed, and there is no error while executing the script
File.txt
Error input.txt got an error while parsing
Info output.txt has no error while parsing
my $var = `grep Error ./File.txt | awk '{print $2}'`;
print "Errored file $var";
Errored file Error input.txt got an error while parsing
I want just the input.txt which gets filtered by awk command but not happening. Please help
The $ in $2 is interpolated by Perl, so the command that the shell receives looks like:
grep Error ./File.txt | awk '{print }'
(or something else if you have recently matched a regular expression with capture groups). The workaround is to escape the dollar sign:
my $var = `grep Error ./File.txt | awk '{print \$2}'`
Always include use strict; and use warnings; in EVERY perl script.
If you had, you'd have gotten the following warning:
Use of uninitialized value $2 in concatenation (.) or string at scratch.pl line 4.
This would've alerted you to the problem in your command, namely that the $2 variable is being interpolated instead of being treated like a literal.
There are three ways to avoid this.
1) You can do what mob suggested and just escape the $2
my $var = `grep Error ./File.txt | awk '{print \$2}'`
2) You can use the qx form of backticks with single quotes so that it doesn't interpolate, although that is less ideal because you are using single quotes inside your command:
my $var = qx'grep Error ./File.txt | awk \'{print $2}\''
3) You can just use a pure perl solution.
use strict;
use warnings;
my ($var) = do {
local #ARGV = 'File.txt';
map {(split ' ')[1]} grep /Error/, <>;
};

redirecting multipiped output to a file handle in perl

I want to redirect this awk output to the file handle but no luck.
Code:
open INPUT,"awk -F: '{print $1}'/etc/passwd| xargs -n 1 passwd -s | grep user";
while (my $input=<INPUT>)
{
...rest of the code
}
Error:
Use of uninitialized value in concatenation (.) or string at ./test line 12.
readline() on closed filehandle INPUT at ./test line 13.
The error message shown is not directly related to the question in the subject.
In order to open a pipe and retrieve the result in Perl you have to add "|" at the very end of the open call.
The error message comes from the fact that Perl interprets the $1 you use in that double-quoted string. However, your intention was to pass that verbatim to awk. Therefore you have to escape the $ on the Perl side with \$.
There's a space missing in front of the /etc/passwd argument.
Summary: this should work better:
open INPUT,"awk -F: '{print \$1}' /etc/passwd| xargs -n 1 passwd -s | grep user|";
However, you should also check for errors etc.
It looks like $1 in the string you've passed is making Perl look for a variable $1 which you've not defined. Try escaping the $ in the string by putting a \ in front of it.
Because the string is not valid it doesn't do the open which then produces your second error.

Perl backticks when using pipes

I'm experiencing some problems trying to capture the output of a simple command:
$timeTotal = `echo $timeTotal + $time | bc -l`;
But I'm getting the following errors:
sh: +: not found
sh: Syntax error: "|" unexpected
This command works perfectly in bash but it seems sh is being actually used. At the very beginning I thought that the problem is the pipe usage (although the sum is not well interpreted neither). What confuses me is that the following command in the same script causes no error and works properly:
my $time = `cat $out.$step | bc -l`;
Any suggestions?
$timeTotal contains a trailing newline it shouldn't, so you're executing
echo XXX
and
+ YYY | bc -l
instead of
echo XXX + YYY | bc -l
You're surely missing a chomp somewhere.
There's also a double-quote in your command that's out of place.
The backticks are deprecated. Use the qx(..) syntax instead.
$timeTotal = qx(echo $timeTotal + $time | bc -l");

Perl wget quotes syntax issue

thank you for reading.
For a shell command to wget, something like this works:
wget -q -O - http://www.myweb.com | grep -oe '\w*.\w*#\w*.\w*.\w\+' | sort -u
However, when I try to insert that command inside the Perl program, then I get a syntax error referring to "backslashes found where operator expected, bareword found where operator expected". So I replaced the quotes that surround the regex by this {} but, what that does is just like commenting it out, it does not bring the error, but it is as if the regex weren't, so obviously the curly braces are a wrong attempt.
This is the code, it is inside a foreach:
foreach(#my_array) {
$browser->get($_);
# and here below is where the error comes
system ('wget -q -O -"$_" | grep -oe '\w*.\w*#.\w*.\w\+' | sort -u');
If I replace the single quotes wrapping the regex by {}, then wget does get the URLs but the grep command does not act.
So that is the issue, how to resolve the quotes annoying the syntax
You are using single-quotes ' in your system call. They do not fill in variables for you. The $_ is not getting replaced. Also, the single quotes next to the grep make this invalid syntax.
Try this instead:
system ("wget -q -O - $_ | grep -oe '\w*.\w*\#.\w*.\w\+' | sort -u");
You can also use the qq operator:
system ( qq( wget -q -O - $_ | grep -oe '\w*.\w*\#.\w*.\w\+' | sort -u) );
Also, look at perlop.
Another thought: If you have $browser object that can get() the url, why do you need to use wget? You could also do this in Perl.
You want this:
system ("wget -q -O -\"$_\" | grep -oe '\\w*.\\w*#.\\w*.\\w\\+' | sort -u");
You can include what you like within double quotes, only you have to escape certain characters.
Incidentally, Perl's qq() operator might interest you. You can look it up.