Perl -e Test Oddity? - perl

Why is this exists check returning different results for pwd versus the other examples? What's happening here?
[me#unixbox1:~/perltests]> cat testopensimple.pl
#!/usr/bin/perl
use strict;
use warnings;
# |<command> for writing
# <command>| for reading
testopen("| pwd");
testopen("pwd |");
testopen("| hostname");
testopen("| cd");
testopen("| sh");
testopen("| sleep 2");
sub testopen {
my $command = shift;
print "Exists: " . (-e $command ? "true" : "false") . "\n";
print "testopen($command)\n";
eval {
open(my $fh, $command) or die "$! $#";
my $data = join('', <$fh>);
close($fh) or die "$! $#";
print $data . "\n";
};
if ($#) {
print $# . "\n";
}
}
[me#unixbox1:~/perltests]> perl testopensimple.pl
Exists: true
testopen(| pwd)
/home/me/perltests
Exists: true
testopen(pwd |)
/home/me/perltests
Exists: false
testopen(| hostname)
unixbox1
Exists: false
testopen(| cd)
Exists: false
testopen(| sh)
Exists: false
testopen(| sleep 2)
Update:
I'm not convinced that it's a shell built-in vs external command issue. Try it with a command like netstat which is external. pwd is the only command I've found thus far that returns true on the exists check with pipes.
Update 2:
Through the several iterations of testing I was doing, files named '| pwd' and 'pwd |' ended up being created. That explains what I'm seeing. Thanks.

-e '| pwd' will only return true if you have a file named | pwd in the current directory.
-e 'pwd |' will only return true if you have a file named pwd | in the current directory.
$ perl -E'say -e "| pwd" ? 1 : 0'
0
$ touch '| pwd'
$ perl -E'say -e "| pwd" ? 1 : 0'
1
$ perl -E'say -e "pwd |" ? 1 : 0'
0
$ touch 'pwd |'
$ perl -E'say -e "pwd |" ? 1 : 0'
1

Related

How to write a Perl script to convert file to all upper case?

How can I write a Perl script to convert a text file to all upper case letters?
perl -ne "print uc" < input.txt
The -n wraps your command line script (which is supplied by -e) in a while loop. A uc returns the ALL-UPPERCASE version of the default variable $_, and what print does, well, you know it yourself. ;-)
The -p is just like -n, but it does a print in addition. Again, acting on the default variable $_.
To store that in a script file:
#!perl -n
print uc;
Call it like this:
perl uc.pl < in.txt > out.txt
$ perl -pe '$_= uc($_)' input.txt > output.txt
perl -pe '$_ = uc($_)' input.txt > output.txt
But then you don't even need Perl if you're using Linux (or *nix). Some other ways are:
awk:
awk '{ print toupper($0) }' input.txt >output.txt
tr:
tr '[:lower:]' '[:upper:]' < input.txt > output.txt
$ perl -Tpe " $_ = uc; " --
$ perl -MO=Deparse -Tpe " $_ = uc; " -- a s d f
LINE: while (defined($_ = <ARGV>)) {
$_ = uc $_;
}
continue {
die "-p destination: $!\n" unless print $_;
}
-e syntax OK
$ cat myprogram.pl
#!/usr/bin/perl -T --
LINE: while (defined($_ = <ARGV>)) {
$_ = uc $_;
}
continue {
die "-p destination: $!\n" unless print $_;
}

perl + set parameter correctly in the syntax

I use the following find command to rename directories & files in Linux system
remark: see rename.pl script down below
find / -name 'host1' -print0 | xargs -0 /var/tmp/rename.pl 'print "changing $_\n"; s/host1/host_10/g'
in order to set parameter in place host1 name I set the following
OLD_HOST=host1
Example:
find / -name "$OLD_HOST" -print0 | xargs -0 /var/tmp/rename.pl 'print "changing $_\n"; s/$OLD_HOST/host_10/g'
the problem is that now after setting the $OLD_HOSTS (as s/$OLD_HOST/host_10/g' )
it doesn't replace host1 with host_10
my question: how to use correctly $OLD_HOST in the syntax in order to replace host1 with host_10 ?
#
rename.pl script:
#!/usr/bin/perl
#
# rename script examples from lwall:
# rename 's/\.orig$//' *.orig
# rename 'y/A-Z/a-z/ unless /^Make/' *
# rename '$_ .= ".bad"' *.f
# rename 'print "$_: "; s/foo/bar/ if <stdin> =~ /^y/i' *
$op = shift;
for (#ARGV) {
$was = $_;
eval $op;
die $# if $#;
rename($was,$_) unless $was eq $_;
}
It's not very clear what you are trying to do.
I guess you are setting
OLD_HOST=host1
in the shell and you are trying to get the value of $OLD_HOST env variable from a Perl script. If so you can make use of
$ENV{'OLD_HOST'}
as:
find / -name "$OLD_HOST" -print0 | xargs -0 /var/tmp/rename.pl 'print "changing $_\n"; s/$ENV{OLD_HOST}/host_10/g'
^^^^^^^^^^^^^^

build perl one-liners from short perl script and combines in to other line

Continue my previous question (but other queastion),
According to the following perl script (rename.pl)
how to build perl one-liners line from the rename.pl script
in order to replace the: /var/tmp/rename.pl (from find command ...)
with the one-liners perl syntax?
(I dont want to use the rename.pl script ,)
find / -name "$OLD_HOST" -print0 | xargs -0 /var/tmp/rename.pl 'print "changing $_\n"; s/$OLD_HOST/host_10/g'
rename.pl script:
#!/usr/bin/perl
$op = shift;
for (#ARGV) {
$was = $_;
eval $op;
die $# if $#;
rename($was,$_) unless $was eq $_;
}
Why not use the bullet-proofed, debugged rename.pl script?
find ... |
xargs -0 perl -e 'my $op - shift; foreach (#ARGV)
{ my $was = $_; eval $op; die $# if $#;
rename($was, $_) unless $was eq $_; }' \
s/x/y/g
This one-liner will find zip files with numbers inside the filename, and print some "mv" shell commands rather than executing them immediately. You can paste this into the command line for more control later.
Maybe this will get you started.
find . -name "*.zip" | perl -nE
'chomp; my $f = qq($_); $f =~ /(\d+)/;
say "mv $f " . sprintf("%03d", $1) . ".zip";'

What's the best way to convert "awk '{print $2 >> $1}' file" in a Perl one-liner?

How could I convert:
awk '{print $2 >> $1}' file
in a short Perl one-liner?
"file" could look like this:
fruit banana
vegetable beetroot
vegetable carrot
mushroom chanterelle
fruit apple
there may some other ways, but here's what i can think of
perl -ane 'open(FILE,">>",$F[0]); print FILE $F[1];close(FILE);' file
I guess awk has to be better at some things :-)
This is right at the limit of what I'd do on the command line, but it avoids reopening filehandles.
$ perl -lane '$fh{$F[0]} || open $fh{$F[0]}, ">>", $F[0]; print {$fh{$F[0]}} $F[1]' file
Not pure Perl, but you can do:
perl -nae '`echo $F[1] >> $F[0]`' input_file
This is what a2p <<< '{print $2 >> $1}' produces
#!/usr/bin/perl
eval 'exec /usr/bin/perl -S $0 ${1+"$#"}'
if $running_under_some_shell;
# this emulates #! processing on NIH machines.
# (remove #! line above if indigestible)
eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_0-9]+=)(.*)/ && shift;
# process any FOO=bar switches
$, = ' '; # set output field separator
$\ = "\n"; # set output record separator
while (<>) {
($Fld1,$Fld2) = split(' ', $_, -1);
&Pick('>>', $Fld1) &&
(print $fh $Fld2);
}
sub Pick {
local($mode,$name,$pipe) = #_;
$fh = $name;
open($name,$mode.$name.$pipe) unless $opened{$name}++;
}

How can I tell if a filehandle is empty in Perl?

For example:
open (PS , " tail -n 1 $file | grep win " );
I want to find whether the file handle is empty or not.
You can also use eof to check whether a file handle is exhausted. Here is an illustration based loosely on your code. Also note the use of a lexical file handle with the 3-arg form of open.
use strict;
use warnings;
my ($file_name, $find, $n) = #ARGV;
open my $fh, '-|', "tail -n $n $file_name | grep $find" or die $!;
if (eof $fh){
print "No lines\n";
}
else {
print <$fh>;
}
Although calling eof before you attempt to read from it produces the result you expect in this particular case, give heed to the advice at the end of the perlfunc documentation on eof:
Practical hint: you almost never need to use eof in Perl, because the input operators typically return undef when they run out of data, or if there was an error.
Your command will produce at most one line, so stick it in a scalar, e.g.,
chomp(my $gotwin = `tail -n 1 $file | grep win`);
Note that the exit status of grep tells you whether your pattern matched:
2.3 Exit Status
Normally, the exit status is 0 if selected lines are found and 1 otherwise …
Also, tail exits 0 on success or non-zero on failure. Use that information to your advantage:
#! /usr/bin/perl
use strict;
use warnings;
my $file = "input.dat";
chomp(my $gotwin = `tail -n 1 $file | grep win`);
my $status = $? >> 8;
if ($status == 1) {
print "$0: no match [$gotwin]\n";
}
elsif ($status == 0) {
print "$0: hit! [$gotwin]\n";
}
else {
die "$0: command pipeline exited $status";
}
For example:
$ > input.dat
$ ./prog.pl
./prog.pl: no match []
$ echo win >input.dat
$ ./prog.pl
./prog.pl: hit! [win]
$ rm input.dat
$ ./prog.pl
tail: cannot open `input.dat' for reading: No such file or directory
./prog.pl: no match []
open (PS,"tail -n 1 $file|");
if($l=<PS>)
{print"$l"}
else
{print"$file is empty\n"}
well ... scratch this ... I didn't make the connection about the filehandle actually being the output of a pipe.
You should use stat to determine the size of a file but you're going to need to
ensure the file is flushed first:
#!/usr/bin/perl
my $fh;
open $fh, ">", "foo.txt" or die "cannot open foo.txt - $!\n";
my $size = (stat $fh)[7];
print "size of file is $size\n";
print $fh "Foo";
$size = (stat $fh)[7];
print "size of file is $size\n";
$fh->flush;
$size = (stat $fh)[7];
print "size of file is $size\n";
close $fh;