marvin_yorke
marvin_yorke

Reputation: 3559

troubles while redirecting stderr in csh

I'm writing a Perl script that should execute commands in shell and parse their output. As a shell I'm intended to use csh. I've started with this

my $out = `cmd`

but it doesn't capture STDERR, which I need too. Running sh with output redirection does nothing

my $out = `sh -c "cmd 2>&1"`

still captures only STDOUT, not STDERR.

Even redirecting to file in csh doesn't work for me

tcsh$ cmd >& logfile.log

still captures STDOUT only %)

The command I'm trying to execute is actuallty sh script and some commands in this script print into STDERR and I want to capture that output. If I execute sh -c "cmd 2>/dev/null" STDERR actually goes to /dev/null and only STDOUT is printed in terminal.

Could anyone help me with this?

Upvotes: 3

Views: 1896

Answers (5)

Joel Berger
Joel Berger

Reputation: 20280

I don't really have time to mock up an example as I normally would, nor even test one. I am thinking that you might try using Capture::Tiny to see if that helps.

Upvotes: 1

Keith Thompson
Keith Thompson

Reputation: 263257

You said that running the command cmd >& logfile.log in tcsh sends only cmd's stdout to the log file, not its stderr. That doesn't make sense.

Try replacing cmd with the following script:

#!/bin/sh

echo stdout
echo STDERR 1>&2

Both "stdout" and "STDERR" should show up in logfile.log.

If so, then perhaps your "cmd" is doing something odd. My best guess is that cmd is writing to /dev/tty, not to either stdout or stderr; that wouldn't be affected by redirection.

To see what I mean, add this line to the above script:

echo tty > /dev/tty

Upvotes: 1

tchrist
tchrist

Reputation: 80384

I believe there is something you are not telling us. Are you on cygwin? Or Windows? Do you have a PERL5SHELL environment variable set?

There is something that you are not telling us because both of these work fine on the five platforms I can easily test on:

% perl -le '$out = `sh -c "grep missing /dev/nowhere 2>&1" | cat -n`; chomp $out; print "got <<<$out>>>"'
got <<<     1   grep: /dev/nowhere: No such file or directory>>>

But in far, there is no reason to call sh(1) explicitly for shelling out. That’s because Perl always calls sh(1) for all its backtick, pipe opens, and system() shell-outs:

% perl -le '$out = `grep missing /dev/nowhere 2>&1 | cat -n`; chomp $out; print "got <<<$out>>>"'
got <<<     1   grep: /dev/nowhere: No such file or directory>>>

The only except to this I can think of occurs on non-Unix systems, where because they have no /bin/sh, something else is defined.

But under no circumstances will simple shell-outs be calling tcsh(1) behind your back. You’d’ve had to’ve seriously hacked the perl(1) source to get that to happen. I also rather doubt you could (easily) hack the binary, since the string "/bin/tcsh" is going to be longer than "/bin/sh", and it isn’t very often going to be found in /bin/ anyway.

That you can’t get stderr redirection working even from the shell says something pretty weird is going on. I think we need more information.

Upvotes: 2

Axeman
Axeman

Reputation: 29854

  • Backquotes capture STDOUT not STDERR.
  • system will dump both stdout and stderr to their parent's settings.
  • If you want to capture STDERR, you need something like IPC::Open3:

Extremely similar to open2(), open3() spawns the given $cmd and connects CHLD_OUT for reading from the child, CHLD_IN for writing to the child, and CHLD_ERR for errors. If CHLD_ERR is false,

Upvotes: 1

Alex Reynolds
Alex Reynolds

Reputation: 96937

Here, you are capturing the STDOUT of sh, which is not the STDERR of cmd:

my $out = `sh -c "cmd 2>&1"`;

Can you just run cmd directly?

my $out = `cmd 2>&1`;

Upvotes: 1

Related Questions