Perl one-liner if else logic - perl

I'm evaluating whether or not certain variables match expected values. The variables are set in memory by a certain program, the values of which can be access from the shell with a custom program.
I'm piping the output of the shell command to awk to get the specific field I want and then I want to run it through perl to see if it matches the expected value. For example,
ysgrp autostart | awk -F\: '{print $1}' | perl -e 'print {"True"} else {print "False"} if /on/'
However, I'm getting complaints from perl about compilation errors near "} else". How does one handle if/then/else logic in a perl one-liner?

You can't use an else condition in a postfix conditional. You can either use a ternary conditional operator like this:
perl -e 'print /on/ ? "True" : "False"'
Or use explicit blocks like this:
perl -e 'if ( /on/ ) { print "True" } else { print "False" }'

This part:
awk -F\: '{print $1}' | perl -e 'print {"True"} else {print "False"} if /on/'
can be handled in perl (if I remember awk correctly):
perl -F/:/ -lane 'print $F[0] =~ /on/ ? "True" : "False"'
Note the use of the -n switch, without which your perl one-liner will not work. Also note the -l switch, which adds a newline to your print, which is something I assume you want. Otherwise your output will be something like:
TrueTrueTrueFalseTrueFalse

You could do:
... | perl -ne 'print /on/ ? "True" : "False"'
but please don't! You'd be better off doing:
... | grep -qF on && echo True || echo False

One does not, except by using the ternary ?: operator; the foo if bar syntax does not support else.

Related

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;

Write valualble the same string in perl?

I have a command in perl
system("grep LISTEN /root/Desktop/m.txt | awk {'print $5'} | cut -f 1 -d ":"| sort | uniq > /tmp/entropy/dsip.txt");
The output error near $5.
How to write $5 the same string, not a valuable ?
Calling awk and cut and sort from Perl? Really? Perl can do all the work itself:
open my $LISTEN, '<', '/root/Desktop/m.txt' or die $!;
my %uniq;
while (<$LISTEN>) {
next unless /LISTEN/;
my $fifth = (split)[4];
$fifth =~ s/:.*//;
undef $uniq{$fifth};
}
print $_, "\n" for sort keys %uniq;
Use non interpolating parentheses,
system(q{grep LISTEN ..});
Just escape the $s:
print "\$literal\n";
to prevent Perl from interfering. Also escape the $s, to prevent shell from interfering:
system("echo \\\$1");
in which case shell will see \$1 and echo will see $1.
awk {'print $5'}
should be
awk '{print $5}'
ikegami says: The above is wrong since the two are equivalent
$ perl -E'say "<$_>" for #ARGV' awk {'print $5'}
<awk>
<{print $5}>
$ perl -E'say "<$_>" for #ARGV' awk '{print $5}'
<awk>
<{print $5}>

How to add blank line after every grep result using Perl?

How to add a blank line after every grep result?
For example, grep -o "xyz" may give something like -
file1:xyz
file2:xyz
file2:xyz2
file3:xyz
I want the output to be like this -
file1:xyz
file2:xyz
file2:xyz2
file3:xyz
I would like to do something like
grep "xyz" | perl (code to add a new line after every grep result)
This is the direct answer to your question:
grep 'xyz' | perl -pe 's/$/\n/'
But this is better:
perl -ne 'print "$_\n" if /xyz/'
EDIT
Ok, after your edit, you want (almost) this:
grep 'xyz' * | perl -pe 'print "\n" if /^([^:]+):/ && ! $seen{$1}++'
If you don’t like the blank line at the beginning, make it:
grep 'xyz' * | perl -pe 'print "\n" if /^([^:]+):/ && ! $seen{$1}++ && $. > 1'
NOTE: This won’t work right on filenames with colons in them. :)½
If you want to use perl, you could do something like
grep "xyz" | perl -p -e 's/(.*)/\1\n/g'
If you want to use sed (where I seem to have gotten better results), you could do something like
grep "xyz" | sed 's/.*/\0\n/g'
This prints a newline after every single line of grep output:
grep "xyz" | perl -pe 'print "\n"'
This prints a newline in between results from different files. (Answering the question as I read it.)
grep 'xyx' * | perl -pe '/(.*?):/; if ($f ne $1) {print "\n"; $f=$1}'
Use a state machine to determine when to print a blank line:
#!/usr/bin/env perl
use strict;
use warnings;
# state variable to determine when to print a blank line
my $prev_file = '';
# change DATA to the appropriate input file handle
while( my $line = <DATA> ){
# did the state change?
if( my ( $file ) = $line =~ m{ \A ([^:]*) \: .*? xyz }msx ){
# blank lines between states
print "\n" if $file ne $prev_file && length $prev_file;
# set the new state
$prev_file = $file;
}
# print every line
print $line;
}
__DATA__
file1:xyz
file2:xyz
file2:xyz2
file3:xyz

Printing reverse complement of DNA in single-line Perl

I want to write a quick single-line perl script to produce the reverse complement of a sequence of DNA. The following isn't working for me, however:
$ cat sample.dna.sequence.txt | perl -ne '{while (<>) {$seq = $_; $seq =~ tr /atcgATCG/tagcTAGC/; $revComp = reverse($seq); print $revComp;}}'
Any suggestions? I'm aware that
tr -d "\n " < input.txt | tr "[ATGCatgcNn]" "[TACGtacgNn]" | rev
works in bash, but I want to do it with perl for the practice.
Your problem is that is that you're using both -n and while (<>) { }, so you end up with while (<>) { while (<>) { } }.
If you know how to do <file.txt, why did you switch to cat file.txt|?!
perl -0777ne's/\n //g; tr/ATGCatgcNn/TACGtacgNn/; print scalar reverse $_;' input.txt
or
perl -0777pe's/\n //g; tr/ATGCatgcNn/TACGtacgNn/; $_ = reverse $_;' input.txt
Or if you don't need to remove the newlines:
perl -pe'tr/ATGCatgcNn/TACGtacgNn/; $_ = reverse $_;' input.txt
If you need to use cat, the following one liner should work for you.
ewolf#~ $cat foo.txt
atNgNt
gatcGn
ewolf#~ $cat foo.txt | perl -ne '$seq = $_; $seq =~ tr/atcgATCG/tagcTAGC/;print reverse( $seq )'
taNcNa
ctagCn
Considering the DNA sequences in single-line format in a multifasta file:
cat multifasta_file.txt | while IFS= read L; do if [[ $L == >* ]]; then echo "$L"; else echo $L | rev | tr "ATGCatgc" "TACGtacg"; fi; done > output_file.txt
If your multifasta file is not in single-line format, you can transform your file to single-line before using the command above, like this:
awk '/^>/ {printf("\n%s\n",$0);next; } { printf("%s",$0);} END {printf("\n");}' <multifasta_file.txt >multifasta_file_singleline.txt<="" p="">
Then,
cat multifasta_file_SingleLine.txt | while IFS= read L; do if [[ $L == >* ]]; then echo "$L"; else echo $L | rev | tr "ATGCatgc" "TACGtacg"; fi; done > output_file.txt
Hope it is useful for someone. It took me some time to build it.
The problem is that you're using -n in the perl flag, yet you've written your own loop. -n wraps your supplied code in a while loop like while(<STDIN>){...}. So the STDIN file handle has already been read from and your code does it again, getting EOF (end of file) or rather 'undefined'. You either need to remove the n from -ne or remove the while loop from your code.
Incidentally, a complete complement tr pattern, including ambiguous bases, is:
tr/ATGCBVDHRYKMatgcbvdhrykm/TACGVBHDYRMKtacgvbhdyrmk/
Ambiguous bases have complements too. For example, a V stands for an A, C, or G. Their complements are T, G, and C, which is represented by the ambiguous base B. Thus, V and B are complementary.
You don't need to include any N's or n's in your tr pattern (as was demonstrated in another answer) because the complement is the same and leaving them out will leave them untouched. It's just extra processing to put them in the pattern.

awk or perl one-liner to print line if second field is longer than 7 chars

I have a file of 1000 lines, each line has 2 words, separated by a space. How can I print each line only if the last word length is greater than 7 chars? Can I use awk RLENGTH? is there an easy way in perl?
#OP, awk's RLENGTH is used when you call match() function. Instead, use the length() function to check for length of characters
awk 'length($2)>7' file
if you are using bash, a shell solution
while read -r a b
do
if [ "${#b}" -gt 7 ];then
echo $a $b
fi
done <"file"
perl -ane 'print if length($F[1]) > 7'
You can do:
perl -ne '#a=split/\s+/; print if length($a[1]) > 7' input_file.txt
Options used:
-n assume 'while () { ... }' loop around program
-e 'command' one line of program (several -e's allowed, omit programfile)
You can use the auto-split option as used by Chris
-a autosplit mode with -n or -p (splits $_ into #F)
perl -ane 'length $F[1] > 7 && print' <input_file>
perl -lane 'print if (length($F[$#F]) > 7)' fileName
or
perl -pae '$_ = "" if (length($F[$#F]) <= 7)' fileName