26

I have a file, someFile, like this:

$cat someFile
hdisk1 active
hdisk2 active

I use this shell script to check:

$cat a.sh
#!/usr/bin/ksh
for d in 1 2
do
    grep -q "hdisk$d" someFile && echo "$d : ok"
done

I am trying to convert it to Perl:

$cat b.sh
#!/usr/bin/ksh
export d
for d in 1 2
do
    cat someFile | perl -lane 'BEGIN{$d=$ENV{'d'};} print "$d: OK" if /hdisk$d\s+/'
done

I export the variable d in the shell script and get the value using %ENV in Perl. Is there a better way of passing this value to the Perl one-liner?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sfgroups
  • 18,151
  • 28
  • 132
  • 204
  • 4
    Why not perform the looping directly in Perl? Then your shell script simply disappears. – FMc Jul 23 '10 at 20:13
  • Instead of using `cat file | perl ...` it is more simple to use `perl ... file`. – TrueY Apr 23 '13 at 22:30

8 Answers8

37

You can enable rudimentary command line argument with the "s" switch. A variable gets defined for each argument starting with a dash. The -- tells where your command line arguments start.

for d in 1 2 ; do 
  cat someFile | perl -slane ' print "$someParameter: OK" if /hdisk$someParameter\s+/' -- -someParameter=$d; 
done

See: perlrun

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Philippe A.
  • 2,885
  • 2
  • 28
  • 37
  • Some many thanks. Never really figured it out. Always wrote a script when needing command line arguments. –  Mar 11 '13 at 08:11
5

Sometimes breaking the Perl enclosure is a good trick for these one-liners:

for d in 1 2 ; do cat kk2 | perl -lne ' print "'"${d}"': OK" if /hdisk'"${d}"'\s+/';done
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Juan Diego Godoy Robles
  • 14,447
  • 2
  • 38
  • 52
4

Pass it on the command line, and it will be available in @ARGV:

for d in 1 2
do
  perl -lne 'BEGIN {$d=shift} print "$d: OK" if /hdisk$d\s+/' $d someFile
done

Note that the shift operator in this context removes the first element of @ARGV, which is $d in this case.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Greg Bacon
  • 134,834
  • 32
  • 188
  • 245
  • It is worth point out that @gbacon has converted `cat a| perl -n` to `perl -n a`. If you give a filename as a parameter to perl it is available to the -n loop. – justintime Jul 23 '10 at 21:33
3

Combining some of the earlier suggestions and adding my own sugar to it, I'd do it this way:

perl -se '/hdisk([$d])/ && print "$1: ok\n" for <>' -- -d='[value]' [file]

[value] can be a number (i.e. 2), a range (i.e. 2-4), a list of different numbers (i.e. 2|3|4) (or almost anything else, that's a valid pattern) or even a bash variable containing one of those, example:

d='2-3'
perl -se '/hdisk([$d])/ && print "$1: ok\n" for <>' -- -d=$d someFile 

and [file] is your filename (that is, someFile).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dblu
  • 131
  • 3
2

If you are having trouble writing a one-liner, maybe it is a bit hard for one line (just my opinion). I would agree with @FM's suggestion and do the whole thing in Perl. Read the whole file in and then test it:

    use strict;
    local $/ = '' ; # Read in the whole file
    my $file = <> ;

    for my $d ( 1 .. 2 )
    {
        print  "$d: OK\n" if  $file =~ /hdisk$d\s+/
    }

You could do it looping, but that would be longer. Of course it somewhat depends on the size of the file.

Note that all the Perl examples so far will print a message for each match - can you be sure there are no duplicates?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
justintime
  • 3,601
  • 4
  • 22
  • 37
1

My solution is a little different. I came to your question with a Google search the title of your question, but I'm trying to execute something different. Here it is in case it helps someone:

FYI, I was using tcsh on Solaris.

I had the following one-liner:

perl -e 'use POSIX qw(strftime); print strftime("%Y-%m-%d", localtime(time()-3600*24*2));'

which outputs the value:

2013-05-06

I was trying to place this into a shell script so I could create a file with a date in the filename, of X numbers of days in the past. I tried:

set dateVariable=`perl -e 'use POSIX qw(strftime); print strftime("%Y-%m-%d", localtime(time()-3600*24*$numberOfDaysPrior));'`

But this didn't work due to variable substitution. I had to mess around with the quoting, to get it to interpret it properly. I tried enclosing the whole lot in double quotes, but this made the Perl command not syntactically correct, as it messed with the double quotes around date format. I finished up with:

set dateVariable=`perl -e "use POSIX qw(strftime); print strftime('%Y-%m-%d', localtime(time()-3600*24*$numberOfDaysPrior));"`

Which worked great for me, without having to resort to any fancy variable exporting.

I realise this doesn't exactly answer your specific question, but it answered the title and might help someone else!

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Clarkey
  • 1,553
  • 5
  • 22
  • 34
0

That looks good, but I'd use:

for d in $(seq 1 2); do perl -nle 'print "hdisk$ENV{d} OK" if $_ =~ /hdisk$ENV{d}/' someFile; done
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Eduardo
  • 7,631
  • 2
  • 30
  • 31
0

It's already written on the top in one long paragraph but I am also writing for lazy developers who don't read those lines.

Double quotes and single quote has big different meaning for the bash.

So please take care

Doesn't WORK perl '$VAR' $FILEPATH

WORKS perl "$VAR" $FILEPATH

itirazimvar
  • 859
  • 1
  • 10
  • 20