Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"

tar, system() & pipes?

by Anonymous Monk
on Jul 17, 2007 at 20:13 UTC ( [id://627115]=perlquestion: print w/replies, xml ) Need Help??

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

I'm needed to do further processing on the contents of a tar file. Manually, I'm simply issue:

$ tar txf syssrc.tgz > /tmp/file create a list of directories & files, but doing this programmatically within a Perl script is giving me problems.

If I don't redirect, the following code works:

#!/usr/bin/perl use strict; use warnings; use Readonly; Readonly my $filename => '/tmp/contents'; my $args = 'tf'; eval { die 'incorrect #command-line arguments' unless @ARGV == 1; # add switches based on filetype if ($ARGV[0] =~ /tgz$/) { $args .= 'z'; } # dump tar contents to file if (system('tar', $args, $ARGV[0]) != 0) { if ($? == -1) { die "failed to execute '$!'"; } elsif ($? & 127) { die sprintf 'child process died with signal %d %s', ($? & 127), (($? & 128) ? 'with coredump' : ''); } else { printf "child process exit value:\t%d\n", ($? >> 8); } } }; if ($@) { $@ =~ s/at $0 line \d+\.$//; print "syntax:\t$0 <filename>\n"; print "error:\t$@\n"; } ..but if I change the <b>system()</b> call to: <code> if (system('tar', $args, $ARGV[0], '>', $filename) != 0) {
I get the following warning:
tar: WARNING! These patterns were not matched: > /tmp/contents child process exit value: 1
...and /tmp/file is not created.

Replies are listed 'Best First'.
Re: tar, system() & pipes?
by philcrow (Priest) on Jul 17, 2007 at 20:29 UTC
    If you pass system a list of arguments, they will be passed as command line arguments to the program. Thus '>' is being treated as a command line argument and not as a shell meta-character.


    The Gantry Web Framework Book is now available.
Re: tar, system() & pipes?
by ikegami (Patriarch) on Jul 17, 2007 at 20:29 UTC

    The > /tmp/file is a *shell* directive, but the shell is not invoked when you use system LIST instead of system EXPR. You're passing > and /tmp/file as arguments to tar, and tar doesn't know what to do with them.

      Thank you for your reply.

      So there isn't a way to spawn piped commands from within a Perl script?

        I think the following is safe on unix platforms:

        my $q_archive = quotemeta($ARGV[0]); my $q_filename = quotemeta($filename); system("tar $args $q_archive > $q_filename")

        It can also be written as

        system("tar $args \Q$ARGV[0]\E > \Q$filename\E")

        quotemeta (called directly or via \Q..\E) will backslash-escape any non-word characters, so the file names can safely contain symbols and spaces.

        If the intention is to read the output file back into your program once tar is finished, you could bypass the filesystem by using a piped-open:

        (See the docs for perlfuncopen and perlopentut)

        # ..................v open TAR, "tar .... |" or die ...; while( <TAR> { ## do stuff with the tar output }

        ## do stuff with the tar output could be as simple as print FILE $_;.

        See also IO::Pipe.

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://627115]
Approved by FunkyMonk
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (4)
As of 2024-04-16 22:32 GMT
Find Nodes?
    Voting Booth?

    No recent polls found