Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Re: Passing commands to subroutines

by JavaFan (Canon)
on Jul 01, 2009 at 15:42 UTC ( [id://776464]=note: print w/replies, xml ) Need Help??


in reply to Passing commands to subroutines

The problem will not only be spaces. Anything that is special to the shell will be a problem. To avoid such problems, don't use 1-arg system. Use multiple arg evocation.

See the system manual page, and the perlipc document for details.

Replies are listed 'Best First'.
Re^2: Passing commands to subroutines
by BioLion (Curate) on Jul 01, 2009 at 16:11 UTC

    This site has a pretty good discussion of these sorts of problems, and helped me in a similar situation.

    In particular this fix worked well for me and seemed fine when moving between Unix and windows (i didn't try anything else)...

    "Spaces could be transparently handled (no pun intended) with U+00A0, a non-breaking space, which in fact it is. Really. If the system is presented with a filename containing U+0020, it just replaces it unilaterally with U+00A0."

    Hope this helps

    UPDATE:

    This clearly isn't how i got round the problem too, as it doesn't get around the original problem (see example below)... Thanks JavaFan

    #!/usr/bin/perl use strict; use warnings; use encoding 'utf8'; my $dir = "/tmp/Foo"; unless (-e $dir){ mkdir $dir or die; } chdir $dir or die; opendir my $dh, $dir or die; my @files = readdir $dh; closedir $dh; print "Got ", scalar @files, " files\n"; foreach my $char ("\x{20}", "\x{A0}") { my $file = "foo{$char}bar"; open my $fh, ">", $file or die; } opendir $dh, $dir or die; @files = readdir $dh; closedir $dh; print "Got ", scalar @files, " files\n"; open my $fh, ">", 'foo baz' || die "Failed to open file : $!"; close $fh || die "Failed to close file : $!"; foreach my $char ("\x{20}", "\x{A0}") { my $file = "foo".$char."baz"; if (-e $file){ print "got it\n" } else { print "not got it...\n"; } } system("cat foo\x{20}baz"); system("cat foo\x{A0}baz");

    Just a something something...
      Replacing characters in file names is just plain wrong in Unix. A space is a space, and not something else. And something that isn't a space, just isn't.
      #!/usr/bin/perl use 5.010; use strict; use warnings; my $dir = "/tmp/Foo"; mkdir $dir or die; chdir $dir or die; opendir my $dh, $dir or die; my @files = readdir $dh; closedir $dh; say "Got ", scalar @files, " files"; foreach my $char ("\x{20}", "\x{A0}") { my $file = "foo{$char}bar"; open my $fh, ">", $file or die; } opendir $dh, $dir or die; @files = readdir $dh; closedir $dh; say "Got ", scalar @files, " files"; __END__ Got 2 files Got 4 files
      See, two different files - one with a space, the other with a non-breaking space. No automatic conversion between them.
Re^2: Passing commands to subroutines
by citromatik (Curate) on Jul 01, 2009 at 17:11 UTC

    Hmmm... the original code redirects the system call:

    executeComm ("program $ref_file > $outfile");

    is there a way to use redirection in a system call using the multiple-arg version? this doesn't work: system ($program, $ref_file, ">",$outfile)

    citromatik

      Your whole reason to use the multiple argument version of system was to avoid having the your arguments treated as anything but literal text.

      And now you're asking why it doesn't work when the code does exactly that.

      If you want redirection, you'll either have to build a shell command or do it yourself (IPC::Run, IPC::Run3, IPC::Open2, IPC::Open3, etc.)

      You'd use fork and exec. Did you read the perlipc manual page I suggested? It contains code that does what you want which you can copy and adjust. I'm not going to cut and paste it for you.
      Given that you're facing a problem with tricky file names, the easiest substitute I could imagine for fixing a line of code like this:
      system("program $ref_file > $outfile");
      would be to do it like this:
      open( PROG, "-|", "program", $ref_file ) or die "can't launch 'program +' on $ref_file: $!\n" open( OUT, ">", $outfile ); while (<PROG>) { print OUT; } close PROG; close OUT;
      That ought to take any sort of goofy file name safely in stride (for both input and output files).
        Probably easier to use one of the IPC:: modules, maybe IPC::Cmd
      Multiple-arg system() doesn't quite work like that (read this). Redirection using the shell metacharacter ">" is handled by the shell, which reads the entire string "program $ref_file > $outfile", parses it, and executes the command with redirection.

      When you do multiple-arg system, you're going raw and skipping the shell (usually). Redirections have to be performed manually and you'll lose some convenience you get with using a shell. Example:
      sub executeComm { my ($outfile, @comm) = @_; print "cmd: <", join("> <" => @comm), ">\n"; # manual redirection - dup(2) STDOUT first open(my $ORIGSTDOUT, ">&" . fileno(*STDOUT)) or die $!; open(*STDOUT, ">", $outfile) or die $!; # run it! my $exit = system @comm; # restore STDOUT open(*STDOUT, ">&=" . fileno($ORIGSTDOUT)) or die $!; print "exit: ", $exit, "\n"; } print "before\n"; executeComm($outfile, $program, $ref_file); print "after\n";

      If you really want a quick-and-dirty fix for your "whitespace-in-filename" problem, place single-quotes around the filenames, as in:
      executeComm ("program '$ref_file' > '$outfile'");

      Now make sure you don't have single-quotes in the filenames...
      Have you read 'perldoc -f system'?
      system "foo >bar";
      invokes the shell, and it is the shell which does redirection (> <)
        <blocquote>Have you read 'perldoc -f system'?

        Yes... that is why I am asking: you are calling system with 1 argument... can you please give me an example like that one (with redirection) using the multiple-arg version?

        citromatik

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://776464]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (2)
As of 2024-04-26 01:17 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found