Link to home
Start Free TrialLog in
Avatar of chintaps
chintapsFlag for Afghanistan

asked on

how to redirect standard error and output from a shell script to a file

Hi all,
    by doing this:

script.sh 2>>output.txt

I am able to run the script and send the errors if any to output.txt but how can I send both the output and errors to output.txt by running the script only once.

Also how I can send errors+output to both screen and output.txt by running the script only once.

Thanks in advance
chintaps
Avatar of cjjclifford
cjjclifford

depends on the shell you are using...

for Bourne Shell, KSH and Bash:

# redirect both to same output file
script.sh >output.txt 2>&1

# redirect separately
script.sh >output.txt 2> error.txt

# redirect stdout to null and save error
script.sh >/dev/null 2> error.txt

SOLUTION
Avatar of cjjclifford
cjjclifford

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial

with tee, the -a flag tells it to append rather than (Default) of clobber.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
manav_manthur, there was no mention in the question of not clobbering, but yes ">>" rather than ">" will append (I mentioned the "tee -a" option myself).

The question involved a statement like

<quote>
script.sh 2>>output.txt
</quote>

Just wanted to bring to notice that the solution above, unlike the command posted in the question itself, will clobber the files. If the author has no problems with this, its his call.

Cheers
Manav


fair enough...

actually, looking at the quote from the question it looks like its a CSH shell - is this correct author?



> CSH shell
Isnt the format same for ksh,bash (any other shell) ??

Manav
nope, AFAIK CSH is broken.... (in particular how it handles file descriptors is broken... a quick google on "csh considered harmful" gives http://www.faqs.org/faqs/unix-faq/shell/csh-whynot/

a quick test highlights that the same format doesn't work:

% python -c "import sys; sys.stderr.write( 'hello ' ); print 'world'" >> /tmp/test1.txt 2>&1
csh: Ambiguous output redirect.

whereas in Bash:

$ python -c "import sys; sys.stderr.write( 'hello ' ); print 'world'" 2>&1 | tee /tmp/test3.txt
hello world
[]$ cat /tmp/test3.txt
hello world
[]$

beg your pardon......Im not able to understand what you are trying to say here.......
<quote>
by doing this:

script.sh 2>>output.txt

I am *able* to run the script ....
</quote>

a '>>' works fine on bash, ksh but not on csh(as you've just shown). And the author says that he *is* able to run th command that uses this form of redirection, he should not be on csh....or am I missing something here??

Manav
Avatar of chintaps

ASKER

its a Bourne shell! thanks for the answers guys!
Both these work:
script.sh >> output.txt 2>&1  ##will append all STDOUT/STDERR to output.txt
script.sh 2>&1 | tee -a output.txt ##will make all STDERR?STDOUT appear on screen and append to output.txtx

the difference is the return code from both! While 1 gives the same code(error if error in script) as a return code 2 actually gives it as true no matter what. So if I do a
if [ $? = 0 ];
after this line its a success always!!! is there a way around this?

Thanks
chintaps
The second command will give the return code of the tee command, not your script.....

Manav



an indirect method may be to touch a file if this succeeds, and check for the existence of the file...(thats what occurs to my bleak mind)

script.sh 2>&1 && touch /tmp/file1 | tee -a output.txt
if [ -a /tmp/file1 ]; then
#script.sh succeeded, do something to celebrate!!
rm /tmp/file1
or should it be
{script.sh 2>&1 && touch /tmp/file1} | tee -a output.txt
There's an example of how to get return values from programs earlier in the pipe than the last one, on that URL regarding CSH being harmful...

to quote:
Consider the pipeline:

    A | B | C

You want to know the status of C, well, that's easy: it's in $?, or
$status in csh.  But if you want it from A, you're out of luck -- if
you're in the csh, that is.  In the Bourne shell, you can get it, although
doing so is a bit tricky.  Here's something I had to do where I ran dd's
stderr into a grep -v pipe to get rid of the records in/out noise, but had
to return the dd's exit status, not the grep's:

    device=/dev/rmt8
    dd_noise='^[0-9]+\+[0-9]+ records (in|out)$'
    exec 3>&1
    status=`((dd if=$device ibs=64k 2>&1 1>&3 3>&- 4>&-; echo $? >&4) |
                egrep -v "$dd_noise" 1>&2 3>&- 4>&-) 4>&1`
    exit $status;

--- End Quote

Making sense of this is a little painful...
for our simple example...
(I don't fully follow what is going on, but I got it to work relatively easily....

exec 3>&1
status=$( ((./script.sh 2>&1 1>&3 3>&- 4>&-; echo $?>&4) | tee /tmp/test.txt 1>&2 3>&- 4>&- ) 4>&1 )
echo $status

The return code gets extracted correctly, but the output mightn't be fully correct... too many angle brackets, and amersands!!!! I'm off home!!


This works fine! thanks guys.