syntax error near unexpected token `|' Perl code - perl

I am trying to execute this in my perl script
my $command = `ps -p $pidnumber | wc -l`;
but when I run the script it show me something like this:
sh: -c: line 1: syntax error near unexpected token `|'
sh: -c: line 1: ` | wc -l'
Which would it may to be the error?

Does $pidnumber end with a new line? See the chomp function.

try print before execute the command, because $pidnumber may have something strange:
my $command_str = "ps -p $pidnumber | wc -l";
print $command_str, "\n";
my $command = qx!$command_str!;
as #mob said, use chomp if newline appears in the print sentence.

I agree with the other answers that an extra newline before the pipe is quite possibly the cause
But the command doesn't really need the pipe!
force the quoted command to return it's value as a list and then get the length of the list and you've got the wc -l "line count"
my $command_str = "ps -p $pidnumber";
my $linecount = () = qx!$command_str!;

Related

Perl - Login to mutiple servers and grep for an error in logs

I'm Trying to login to multiple servers and grep for a specific error in the logs. If the error is found then output the hostname of the server and how many times the error occurred
CODE:
#!/usr/bin/perl
use diagnostics;
use warnings;
my $uid = $ENV{'LOGNAME'};
my $server;
my #hosts = ('server1','server2','server3','server4','server5','server6','server7','server8');
print "Log Date (MM-DD): ";
my $LD8 = <STDIN>;
print "host Error Occured \n";
print "-------------- ---------------\n";
for each $server (#hosts) {
open my $tc, 'ssh -q $uid#$server "grep -c 'Error Occured' /home/perry/error.log-$LD8"', or die "could not run";
while (<$tc>) {
print "$server '$_'\n";
} #--while
} #--for
close $tc;
This code:
open my $tc, 'ssh -q $uid#$server "grep -c 'Error Occured' /home/perry/error.log-$LD8"'
Is problematic for a number of reasons. You probably want the variable names $uid, $server and $LD8 to be replaced with the contents of those variables. But the string uses single quotes - which is what you use when you don't want variables to be interpolated. Also, the string contains single quotes, so it's probably triggering a syntax error.
To make it more challenging, your string also contains double quote characters. You could backslash-escape them like this:
open my $tc, "ssh -q $uid#$server \"grep -c 'Error Occured' /home/perry/error.log-$LD8\""
Or you could use the qq() operator as alternative double quote delimiters.
open my $tc, qq(ssh -q $uid#$server "grep -c 'Error Occured' /home/perry/error.log-$LD8")
But there's still a problem because that string is a command but you're passing it to open as if it was a filename so it's still not going to work. If you want open to treat the argument as a command and run it, with its STDOUT attached to a pipe, so that you can read from the pipe to get the command's output, then you need to add a pipe character (|) as the last character in the string:
open my $tc, qq(ssh -q $uid#$server "grep -c 'Error Occured' /home/perry/error.log-$LD8" |)

quoting {print $NF} inside layers of single and double quotes?

Stuck trying to figure out how to single quotes withing single quotes within double quotes. Here's what I'm trying to do....
From perl, I want to run a system command that...
- does an ssh into a remote machine
- executes 'uptime' and then plucks the last field out of that (avg load last 15 min).
\#\!/usr/bin/env perl
my $cmd = "ssh othermachine 'uptime | awk '{print $NF}'' > local_file.dat";
system($cmd);
Of course this won't run ...
% ./try.pl
Missing }.
%
Missing "}" ??? Looks like it's interpreting the $NF} as a var? I tried escaping the {} chars with no luck. I tried escaping the $, no luck. I tried a space before the }, no luck but different msg (Undefined variable).
c-shell BTW and thanks in advance !
You want the following to be ssh's second argument:
uptime | awk '{print $NF}'
To do that, you simply placed single quotes around it. But that doesn't work because it contains single quotes.
You want to build a string that contains $NF, but you did it as follows:
"...$NF..."
That will place the value of (non-existent) Perl variable $NF in the string.
Do it step by step.
Static:
Remote command:
uptime | awk '{print $NF}'
Local command:
ssh othermachine 'uptime | awk '\''{print $NF}'\''' >local_file.dat
String literal:
my $local_cmd = q{ssh othermachine 'uptime | awk '\''{print $NF}'\''' >local_file.dat}
Dynamic:
use String::ShellQuote qw( shell_quote );
my $remote_cmd = q{uptime | awk '{print $NF}'};
my $local_cmd = shell_quote('ssh', 'othermachine', $remote_cmd) . ' >local_file.dat';
Use Net::OpenSSH and let it do the quoting for you:
use Net::OpenSSH;
my $ssh = Net::OpenSSH->new($othermachine,
remote_shell => 'tcsh');
$ssh->system({stdout_file => 'local_file.dat'},
'uptime', \\'|', 'awk', '{print $NF}')
or die "ssh command failed: " . $ssh->error;

Escaping pipe in perl

I'm having some trouble with backtics and pipe in perl. I have following code:
my #arr_lsdev = `lsdev -C | grep inet | awk '{print \$1}'` ;
print Dumper #arr_lsdev ;
But I get following error:
sh[2]: 0403-057 Syntax error : `|' is not expected
I'm guessing it has something to with my escape commands. I have tried escaping the | but it still results in the same error.
OS: AIX
Shell: KSH
Notice that the error is on line 2. You are actually executing
my #arr_lsdev = `lsdev -C | grep inet
| awk '{print \$1}'` ;
You can reduce the number of pipes:
my #arr_lsdev = map {(split ' ')[0]} grep {/inet/} `lsdev -C`;

Perl perform a pgrep with count line

I've got a problem using pgrep with the wc command. I find 2 lines where I only expect 1 line.
my $test = `pgrep -f 'blabla'`;
print $test; <------ print the good PID (only one)
my $test = `pgrep -f 'blabla'|/usr/bin/wc -l`;
print $test; <------- print 2 and a carriage return
I find that a carriage return is inserted before the pipe, so wc counts 2 lines.
Is there a way to do a intermediate chomp() beetween the pipe ?
Thank you for your help
pgrep is matching itself when you use a pipe. This can be verified if you pipe into cat instead of wc. You can avoid this by adding in some braces like so, so that the pattern no longer matches itself.
my $test = `pgrep -f '[b]labla' | /usr/bin/wc -l`;

Substituting path

I want to replace path in
(setq myFile "/some/path")
in a file. I tried to do it with sed:
find ./_build/html -type f -name '*.html' | while read myFile; do
MyFile=`readlink -f "$myFile"`
sed -i "s/setq myFile [)]*/setq myFile \"$MyFile\"/" sphinx_nowrap.el
# and then some actions on file
done
and with perl:
find ./_build/html -type f -name '*.html' | while read myFile; do
MyFile=`readlink -f "$myFile"`
perl -ne "s/setq myFile .+/setq myFile \"$MyFile\")/" sphinx_nowrap.el
# and then some actions on file
done
but both give errors.
I've read this and this and also this -- but can't make it work.
Edit:
Here's a perl error:
Having no space between pattern and following word is deprecated at -e line 1.
Bareword found where operator expected at -e line 1, near "s/setq myFile .+/setq myFile "/home"
String found where operator expected at -e line 1, at end of line
(Missing semicolon on previous line?)
syntax error at -e line 1, near "s/setq myFile .+/setq myFile "/home"
Can't find string terminator '"' anywhere before EOF at -e line 1.
and here's sed error:
sed: -e expression #1, char 34: unknown option to `s'
Edit 2:
So the solution is to change the delimeter char. And also sed expression should be changed:
sed -i "s!setq myFile .*!setq myFile \"$MyFile\")!" sphinx_nowrap.el
Looks like perl (and sed) recognizes the slash in the file path as the regex delimiter. You can use a different delimiter:
find ./_build/html -type f -name '*.html' | while read myFile; do
MyFile=`readlink -f "$myFile"`
perl -ne "s!setq myFile .+!setq myFile \"$MyFile\")!" sphinx_nowrap.el
# and then some actions on file
done
or for sed:
find ./_build/html -type f -name '*.html' | while read myFile; do
MyFile=`readlink -f "$myFile"`
sed -i "s!setq myFile [)]*!setq myFile \"$MyFile\"!" sphinx_nowrap.el
# and then some actions on file
done
Lets assume your $MyPath hold /foo/bar/baz. Then the Perl code reads as:
perl -ne "s/setq myFile .+/setq myFile \"/foo/bar/baz\")/" sphinx_nowrap.el
Your Regex is terminated with the third / character. To work around this, we can use another delimiter like s{}{}:
perl -ine "s{setq myFile .+}{setq myFile \"/foo/bar/baz\")}; print" sphinx_nowrap.el
I also added the -i Option (inplace editing) and a print statement so that something actually gets print out.
But probably it would be more elegant to pass the value aof $MyPath as a command line argument:
perl -ne 's{setq myFile .+}{setq myFile "$ARGV[0]")}; print' $MyPath <sphinx_nowrap.el >sphinx_nowrap.el