mrbbq has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks - I am working on a script and I am stuck. I have scoured the web but I must be asking the wrong questions. I have this sub that takes information from another piece of perl code. it looks like this:
$ejected_tapes=0 ; my @tapes_to_eject=@_ ; # Going to add the file checks and date stuff in perl – ongoing # We are going to have to generate a unique file # Todo: make better use of array itteration $stamp=`/bin/date +%Y%m%d%H%M%S`; `/bin/touch /u01/scripts/logs/$stamp.tapes`; $file="/u01/scripts/logs/$stamp.tapes"; # Now lets open a unique file and not worry about deleting each time open (MYFILE, '>>$file'); print MYFILE "$\@_[0]:$\@_[1]:$\@_[2]:$\@_[3]:$\@_[4]:$\@_[5]:$\@_[6]: +$\@_[7]:$\@_[8]:$\@_[9]:$\@_[10]:$\@_[11]:$\@_[12]:$\@_[13]:$\@_[14]" +; close (MYFILE); $media_list=`/bin/cat /u01/scripts/logs/$file`; If ( $ejected_tapes == $maxslots ) { print "The export door in robot $robot_num only holds $maxslot +s tape(s), \n"; print "and BLAM has now ejected that many tapes. Please go and + empty the\n"; print "import/export doors and press <RETURN> when you're fini +shed"; $ready=<STDIN>; $ejected_tapes=0; } `/usr/openv/volmgr/bin/vmchange -res -multi_eject -w -verbose +-rn $robot_num -rt tld -rh $robot_host -ml $media_list` ; }
ultimatly the $media_list var should just be a list of number:number:number etc. I pass it this through a file right now that I have to manually zero out each time I run the script. I want to create a file or blat the number out of the array directly to the command. Can someone give me a hint on how to do either? Thanks.

Replies are listed 'Best First'.
Re: Help With Perl and Files
by toolic (Bishop) on Sep 27, 2007 at 20:40 UTC
    It is not clear to me what you are trying to achieve, but one way to create a colon-separated string from all elements of an array is to use join.
    #!/usr/bin/env perl use warnings; use strict; my @list = (5..10); print "list = @list\n"; foo(@list); exit; sub foo { my $media_list = join ':', @_; print "media_list = $media_list\n"; }
    Produces the following output:
    list = 5 6 7 8 9 10 media_list = 5:6:7:8:9:10
    Additionally, the code you provided does not compile, and has other issues which can be resolved using the strictures (use strict; and use warnings;).
Re: Help With Perl and Files
by perlfan (Parson) on Sep 27, 2007 at 20:54 UTC
    Instead of
    open (MYFILE, '>>$file'); print MYFILE "$\@_[0]:$\@_[1]:$\@_[2]:$\@_[3]:$\@_[4]:$\@_[5]:$\@_[6]: +$\@_[7]:$\@_[8]:$\@_[9]:$\@_[10]:$\@_[11]:$\@_[12]:$\@_[13]:$\@_[14]" +; close (MYFILE);
    Simply use:
    open (MYFILE, '>>$file'); print MYFILE join(":",@tapes_to_eject); close (MYFILE);
    Also,why are you escaping to shell to touch the file? open takes care of this. You should also get the date using a Perl idiom, not the system's date utility.

    If you want to use system utilities like this, you might be better of just writing a shell script.
      Hey, thanks for the response...I was confused about using open - I thought the file had to exist first and was just making it more difficult. When I get frustrated with perl I escape to shell until I can get it worked out with perl. Your post really helped and led me down the right path. Thanks.
Re: Help With Perl and Files
by johngg (Canon) on Sep 27, 2007 at 22:49 UTC
    toolic and perlfan have given you some pointers. There are a couple of slight oddities in your code. Leaving aside whether to shell out to /bin/date and /bin/touch, changing the order of your statements would save some redundancy.

    $stamp=`/bin/date +%Y%m%d%H%M%S`; $file="/u01/scripts/logs/$stamp.tapes"; `/bin/touch $file`;

    Later on you do

    $media_list=`/bin/cat /u01/scripts/logs/$file`;

    so you are cat'ing the file "/u01/scripts/logs//u01/scripts/logs/$stamp.tapes" which is probably not what you intended.

    I hope this helps you.

    Cheers,

    JohnGG

Re: Help With Perl and Files
by graff (Chancellor) on Sep 28, 2007 at 02:17 UTC
    I'm surprised (shocked... SHOCKED!) that others didn't mention it yet, but every time you do this:
    $stamp=`/bin/date +%Y%m%d%H%M%S`; `/bin/touch /u01/scripts/logs/$stamp.tapes`;
    (update: sorry... I mean every time you do this:)
    $stamp=`/bin/date +%Y%m%d%H%M%S`; ... $file="/u01/scripts/logs/$stamp.tapes"; open( MYFILE, ">>$file");
    you are creating a file in "/u01/scripts/logs/" that contains a line-feed character in the file name (between the last digit and the ".tapes"), because the return value from the first back-tick command includes the "\n" at the end of the output from /bin/date.

    I don't know about you, but personally I hate it when I discover files that contain a line-feed in the middle of the file name. Crap like that can really ruin your day. I like using the POSIX module for getting date/time strings:

    use POSIX; my $stamp = strftime( "%Y%m%d%H%M%S", localtime ); print ">>$stamp<<\n"; # look ma! no line-feed!
    If you want to keep using back-ticks anyway, you'll need to figure out when it's appropriate/necessary to use "chomp".

    (update:) ... Ooops -- I was forgetting an important detail about how back-tick strings work in perl. Whenever you use that $file name (with the line-feed in it) in a back-tick command, you are actually running TWO shell commands, like this:

    /bin/cat 20070925133445 .tapes
    Well, if there is ever an executable file called ".tapes" in you PATH, you'll have a wonderful time figuring out what really happened and why it happened.

    Last update: It's not the sort of thing I like to experiment with but here's a harmless proof-of-concept -- check the difference between these two one-liners:

    perl -e '$_ = `echo foo echo bar`; print' perl -e '$_ = `echo foo\necho bar`; print'