Capture stderr stdout using system call with commas?

Discussion in 'Perl Misc' started by Marv, Feb 2, 2004.

  1. Marv

    Marv Guest

    Hello,

    I've got an issue that I can't seem to figure out.

    I'm trying to run some mount and rsync commands from inside a perl
    script.

    I've figured out from other postings that you have to use a system
    call and seperate all the command line options with quotes and commas.
    I'm not sure why this is, but I can never get the commands to work if
    I enclose them with backticks? Can anybody explain this?

    Anyway, if the commands could be enclosed in backticks I would have my
    problem solved, but since I have to use system (), I can't seem to
    figure out how to capture this data either to a variable or a file.
    I've tried using '2>&1 tmp.errors' but this doesn't work either
    because of the commas. Here is a sample of what I'm doing:

    system (
    "mount",
    "-r",
    "-t",
    "smbfs",

    "-o","username=$adminuser,password=$adminpass",
    "//$ip/$ashare",
    "/share/$nbname/$ashare",
    "2>&1 tmp.errors"
    );

    This method doesn't work because it takes the '2>&1 tmp.errors' as
    another option of mount and bombs out. If I include it at the end of
    '/share/$nbname/$ashare' then it takes as part of the name of the
    mount point and bombs out.

    Can anybody help me capture this info? Or show me how this can be down
    with backticks.

    Thanks.
    Marv
     
    Marv, Feb 2, 2004
    #1
    1. Advertising

  2. In article <>,
    Marv <> wrote:
    > system (
    > "mount",
    > "-r",
    > "-t",
    > "smbfs",
    >
    >"-o","username=$adminuser,password=$adminpass",
    > "//$ip/$ashare",
    > "/share/$nbname/$ashare",
    > "2>&1 tmp.errors"
    > );
    >
    >This method doesn't work because it takes the '2>&1 tmp.errors' as
    >another option of mount and bombs out. If


    Before I answer the question you asked, can I suggest that "2>&1
    tmp.errors" is not doing what you expect? "2>&1" tells the shell that
    the error output should go to the same place as the regular output,
    probably to the terminal. "tmp.errors" will be taken as just another
    argument to mount, the same as if you had put it *before* the "2>&1".
    They are not related.

    If what you want is to send all output to "tmp.errors", you would need

    >tmp.errors 2>&1


    which says to send the normal output to tmp.errors, and then the error
    output to the same place.

    ***

    That said, you can't do this with the list form of 'system'. The
    '2>&1' notation is a message to the Unix shell, and the list form of
    'system' doesn't use the shell---in fact, that's the whole reason that
    the list form of 'system' exists.

    You have at least two choices. You can use the one-argument form of
    'system', which does use the Unix shell:

    system("mount -r -t smbfs -o username=$adminuser,password=$adminpass //$pi/$ashare /share/$nbname/$ashare >tmp.errors 2>&1") == 0
    or die ...;


    or you can do what the shell does when the shell interprets '2>&1',
    which would look something like this:

    my $pid = fork; # Create child process for 'mount' command
    die ... unless defined $pid;
    if ($pid == 0) { # child process
    open STDOUT, ">", "tmp.errors" or die ...; # Redirect STDOUT
    open STDERR, ">&STDOUT" or die ...; # Redirect STDERR
    exec "mount", "-r", "-t", "smbfs", "//$ip/$ashare",
    "-o","username=$adminuser,password=$adminpass",
    "/share/$nbname/$ashare"
    or die ...;
    }
    # Parent process
    wait() or die ...;

    I hope this is at least a little helpful.

    Now, to your root problem:

    >I'm not sure why this is, but I can never get the commands to work if
    >I enclose them with backticks? Can anybody explain this?


    In my experience, one of the sure ways to not get a useful answer to
    your question is to ask why something "doesn't work". To get a useful
    answer, you need to say what you wanted it to do, and what it did do
    that you didn't like. When I saw this I thought immediately that your
    problem was that you weren't getting any output, but then I realized
    that that probably wasn't it. But having guessed wrong at once makes
    me think that guessing again is unlikely to hit on the right problem.
    I could spend a lot of time diagnosing a problem and telling you how
    to fix it only to find out that it wasn't the problem you were
    actually having. And I don't want to do that, having learned from
    hard experience how frustrating it can be for both of us. Someone
    with less hard experience might just go ahead and diagnose and explain
    some random problem that occurred to them, which would be frustrating
    for both of you.

    A good way to ask this kind of question in the future would be to try
    to write a fresh program, as small as possible, that demonstrates your
    one problem as clearly as possible, and nothing else, and then post
    that program, and say "it did X, but I wanted it to do Y". Then you
    will get a lot of useful advice.

    Best regards,
    -D.
     
    Mark Jason Dominus, Feb 2, 2004
    #2
    1. Advertising

  3. Marv wrote:
    > Hello,
    >
    > I've got an issue that I can't seem to figure out.
    >
    > I'm trying to run some mount and rsync commands from inside a perl
    > script.
    >
    > I've figured out from other postings that you have to use a system
    > call and seperate all the command line options with quotes and commas.
    > I'm not sure why this is, but I can never get the commands to work if
    > I enclose them with backticks? Can anybody explain this?
    >
    > Anyway, if the commands could be enclosed in backticks I would have my
    > problem solved, but since I have to use system (), I can't seem to
    > figure out how to capture this data either to a variable or a file.
    > I've tried using '2>&1 tmp.errors' but this doesn't work either
    > because of the commas. Here is a sample of what I'm doing:
    >
    > system (
    > "mount",
    > "-r",
    > "-t",
    > "smbfs",
    >
    > "-o","username=$adminuser,password=$adminpass",
    > "//$ip/$ashare",
    > "/share/$nbname/$ashare",
    > "2>&1 tmp.errors"
    > );
    >
    > This method doesn't work because it takes the '2>&1 tmp.errors' as
    > another option of mount and bombs out. If I include it at the end of
    > '/share/$nbname/$ashare' then it takes as part of the name of the
    > mount point and bombs out.
    >
    > Can anybody help me capture this info? Or show me how this can be down
    > with backticks.
    >

    Your problem is that you are providing the parameters to system() in a list
    context. When you do this, system() calls the program directly, passing the
    rest of the list to the program as parameters. mount can't do output
    redirection; that's a function of the command shell. You want system() to
    invoke the command shell to do your output redirection and have that shell
    start mount with the redirection in place. system() can be invoked so that
    your command line is passed to the shell. To do that, you give it one
    parameter--a string containing your command line, like so, also fixing
    your output redirection syntax:

    system("mount -r -t smbfs -o username=$adminuser,password=$adminpass \
    //$ip/$ashare /share/$nbname/$ashare 2> tmp.errors");

    Or "> tmp.errors 2>&1" if you wanted both stdout and stderr to go to
    tmp.errors.

    Chris Mattern
     
    Chris Mattern, Feb 2, 2004
    #3
  4. Marv wrote:
    > Hello,
    >
    > I've got an issue that I can't seem to figure out.
    >
    > I'm trying to run some mount and rsync commands from inside a perl
    > script.
    >
    > I've figured out from other postings that you have to use a system
    > call and seperate all the command line options with quotes and commas.
    > I'm not sure why this is, but I can never get the commands to work if
    > I enclose them with backticks? Can anybody explain this?
    >
    > Anyway, if the commands could be enclosed in backticks I would have my
    > problem solved, but since I have to use system (), I can't seem to
    > figure out how to capture this data either to a variable or a file.
    > I've tried using '2>&1 tmp.errors' but this doesn't work either
    > because of the commas. Here is a sample of what I'm doing:
    >
    > system (
    > "mount",
    > "-r",
    > "-t",
    > "smbfs",
    >
    > "-o","username=$adminuser,password=$adminpass",
    > "//$ip/$ashare",
    > "/share/$nbname/$ashare",
    > "2>&1 tmp.errors"
    > );
    >
    > This method doesn't work because it takes the '2>&1 tmp.errors' as
    > another option of mount and bombs out. If I include it at the end of
    > '/share/$nbname/$ashare' then it takes as part of the name of the
    > mount point and bombs out.
    >
    > Can anybody help me capture this info? Or show me how this can be down
    > with backticks.
    >
    > Thanks.
    > Marv
    >


    I have several perl scripts that run as cron jobs and I want to capture
    all the output into a log file for later review. I use a two stage
    approach to do this. The cron job is a shell script that runs the perl
    program.

    This is a snip of the perl portion. The main concept came from the Perl
    Cookbook, O'Reilly, ISBN 1-56592-243-3.
    ------------- snippet -------------
    my @archiveDir = ("/mnt/Archives", "/tmp", "/root");

    foreach my $var ( @archiveDir) {
    my $args = "$var/\*$cleanDate\*";

    print "Removing files matching [$args]\n";
    print "\tRunning [rm -f $args]\n";

    open (MyCmd, "rm \-f $args |") or die "Can't run program: $!\n";
    while (<MyCmd>) {
    my $output .= $_;
    print $output;
    }
    close (MyCmd);
    }
    -------------- end snippet ----------

    The shell script which executes the perl program clean-archive is as
    follows.

    #!/bin/bash
    #
    runDate=`date +%F`
    logFile=/root/clean-archive-$runDate.log
    /root/clean-archive > $logFile 2>&1


    While this may not be the most elegant approach I find it works well for
    me. In any case, it's another varient for your consideration.


    --
    Les Hazelton
    Registered Linux user # 272996

    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.2.2 (GNU/Linux)
    Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

    iD8DBQFAH8EvoMRiAeiXZ8MRAsPpAJ4xUM4zxQwNfdonuBX6khPipCvRHQCfQeYX
    g7mC/66tlJkRXOgLj4c98P0=
    =k+6h
    -----END PGP SIGNATURE-----
     
    Leslie Hazelton, Feb 3, 2004
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    3
    Views:
    11,520
  2. AviraM
    Replies:
    2
    Views:
    6,471
    Manish Pandit
    Sep 28, 2006
  3. Damphyr
    Replies:
    2
    Views:
    218
    Damphyr
    Dec 8, 2005
  4. Marcus Bristav
    Replies:
    1
    Views:
    158
    Chris Hulan
    Jan 30, 2008
  5. Gyruss
    Replies:
    7
    Views:
    233
    Brian McCauley
    Jan 15, 2005
Loading...

Share This Page