Capture stderr stdout using system call with commas?

M

Marv

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
 
M

Mark Jason Dominus

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.
 
C

Chris Mattern

Marv said:
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
 
L

Leslie Hazelton

Marv said:
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-----
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top