LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-25-2010, 10:41 AM   #16
druuna
LQ Veteran
 
Registered: Sep 2003
Posts: 10,532
Blog Entries: 7

Rep: Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405

Hi,

Have a look here: Chapter 20. I/O Redirection -> 20.1 Using exec (also suggested by crts)

This shows you how to create other file descriptor then the standard 0, 1 and 2.

Example 20.2 (Redirecting stdout using exec) has the answer to your 2nd question. Opening a specific descriptor, which you can close (restore) at any moment.

About question no 1: Can't you use if then (else) fi for that?

Hope this helps.

Edit: Too slow, catkin has something similar to the ABSG....

Last edited by druuna; 08-25-2010 at 10:42 AM. Reason: Too slow.....
 
Old 08-25-2010, 05:29 PM   #17
crts
Senior Member
 
Registered: Jan 2010
Posts: 2,020

Rep: Reputation: 757Reputation: 757Reputation: 757Reputation: 757Reputation: 757Reputation: 757Reputation: 757
Ok ... I am assuming you are having similar trouble understanding the file descriptors as I did. Let us have a look at the following
{ configure_commands 3>&1 1>&2 2>&3 | tee "$HOME/configure.err" ;} &>"$HOME/configure.log"

When I first saw that I had some trouble understanding why this catches stderr in a separate log. stderr and stdout are being switched so that error messages are being sent to stdout and "normal" messages go to stderr. That is what enables us to catch error messages in a dedicated logfile, since a pipe connects the first programs stdout with stdin of the second command. The redirections outside the {} then catches all output in a single file.

Furthermore confusing was the fact, that the redirections are "order" sensitive. The above statement is NOT equivalent to
{ configure_commands 3>&1 2>&3 1>&2 | tee "$HOME/configure.err" ;} &>"$HOME/configure.log"

This will generate two logfiles which catch the output of both stderr and stdout. I found the following way of looking at it as helpful to understand what happens:
Do not think of fd1 and stdout as one and the same thing. Think of stdout of some immutable object that cannot be redirected. fd1 is a variable (or pointer) that points to stdout. Think of fd2 accordingly. So you have something like this
Code:
pointer   to    Object
 fd1     --->   STDOUT
 fd2     --->   STDERR
STDOUT and STDERR are only accessible for us by using the filedescriptors fd1 and fd2. Now let us see what happens when you do something like
2>&1
You are pointing the "variable" fd2 to the same address that fd1 points to. Notice the similarity of the addressOf operator & in c/c++. Now what does our "reference table" look like?
Code:
pointer   to    Object
 fd1     --->   STDOUT
 fd2     --->   STDOUT
 ???     --->   STDERR
As you see, there is no variable (i.e. filedescriptor) which points to STDERR anymore. Since we can only access it by a filedescriptor we now have "lost" STDERR. And that is why at this point
1>&2

will not achieve our intended switching of STDOUT and STDERR. To stay in the world of c: We are assigning to the variable fd1 the same object that fd2 is pointing to. Since we already pointed fd2 to fd1, we are now pointing fd1 to STDOUT again. No change at all happened.

Have a look at the first statement again:
configure_commands 3>&1 1>&2 2>&3 | tee "$HOME/configure.err"
Code:
3>&1 implicitly creates an additional filedescriptor and points it to fd1. This what our table looks like now
pointer   to    Object
 fd1     --->   STDOUT
 fd2     --->   STDERR
 fd3     --->   STDOUT

1>&2:
pointer   to    Object
 fd1     --->   STDERR
 fd2     --->   STDERR
 fd3     --->   STDOUT

2>&3:
pointer   to    Object
 fd1     --->   STDERR
 fd2     --->   STDOUT
 fd3     --->   STDOUT
At no point one of the streams got lost. They were always referenced by at least one file descriptor.

There is at least one other (right) way than
3>&1 1>&2 2>&3
to arrange these redirections and end up with the same result (switch fd1 and fd2). You might want to try to find it out.

Hope this helps.

Last edited by crts; 10-20-2010 at 09:02 AM. Reason: codetags for nicer format
 
1 members found this post helpful.
Old 08-25-2010, 09:43 PM   #18
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,008

Original Poster
Rep: Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193
Thanks for everyone's input

@crts - thanks for suing some lingo I could understand, as yes file descriptors often confuse the crap outta me

So I am a lot closer to what I want (greedy I know), but question one (which seemed obvious to me but I can now see why it reads like crap)
is still proving elusive.

Yes druuna it would be an if, but my problem is if 'what' or more importantly if true ... do 'what'.
Being that I explained it poorly I will show where I am up to and try and go from there:
Code:
exec 3>&1 1>&2 2>&3

if <true>
then
    <not sure here>
else
    exec &> logfile
fi

<do some stuff that has errors and normal output>

exec 2>&1 1>&3 3>&-
<do some other stuff>
So the <not sure here> is where I would like to say that both stdout / stderr are sent to the logfile and back to stdout

I assume a tee needs to be introduced, but after trying several combinations of exec (maybe not supposed to use this?) I was unable to get it to go to both mediums.
I am feeling like a bit of a dummy with this one so be gentle <larf>
 
Old 08-25-2010, 11:41 PM   #19
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
Maybe you need
Code:
exec 3>&1 4>&2  # separated for lesser confusion
exec &> >(exec tee logfile)
# or
exec >(exec tee logfile) 2>&1
PIDOFTEE=$!

...

kill "$PIDOFTEE"
exec >&- 2>&-; exec >&3 2>&4; exec 3>&- 4>&- # separated for lesser confusion
You can use tee -a for appending.

Edit: Maybe you no longer have to save $! and kill PIDOFTEE... you just need to close the pipe and the tee will automatically close.

Last edited by konsolebox; 08-25-2010 at 11:45 PM.
 
Old 08-26-2010, 02:03 AM   #20
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,008

Original Poster
Rep: Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193
So I went with this information konsole, but it doesn't seem to work as expected

I seem to be getting the problem that crts described in post #6
Quote:
Originally Posted by crts
However, I do recall this thread that described a problem about mixed up order of messages.
Here is what I have tried:

Exactly what you have with a couple of echoes, a ls and a non-existent command to produce an error. My extras look like:
Code:
echo starting
ls *
blah
echo finished

# and after closing descriptors
echo tada
These 5 lines were used in all of the following scenarios.

a. exec >(exec tee logfile) 2>&1 - this produces the following errors and an empty logfile:
Quote:
./test.sh: line 6: /dev/fd/63: Permission denied
./test.sh: line 6: exec: /dev/fd/63: cannot execute: Permission denied
b. exec &> >(exec tee logfile) - output is only the line 'tada' and no logfile

c. same as 'b' but remove the PIDOFTEE references - the output is as expected except the last 2 lines are reversed
ie tada appears before finished. The logfile is created and correctly does not display the word tada

d. Changed the file descriptor setup as follows:
Code:
#first line
exec 3>&1 1>&2 2>&3

#line to close descriptors
exec 2>&- >&3 3>&-
This had the interesting affect of displaying as follows:
Quote:
starting
file1
file2
tada
<cli prompt> ./test.sh: line 10: blah: command not found
finished
[blank line waiting for input]
Had to press enter to complete script. logfile crated again with correct data

e. Changed the closing descriptors line to:
Code:
exec 2>&1 >&3 3>&-
This had the same affect as 'c'

Anyone got any suggestions??
 
Old 08-26-2010, 04:59 AM   #21
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,008

Original Poster
Rep: Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193
Well after a few hours of playing with different combinations I have discovered two things:

1. Apparently I must use 2 descriptors (could not find a combination that worked with only 1 )

2. Only way to guarantee not to have unreliable output after closing descriptors is to through a sleep into the mix (not very clean but it works)

So unless anyone has a better idea, the following seems to be the go:
Code:
#!/bin/bash

exec 3>&1 4>&2

if (( $# > 0 )) # arbitrary test to see if it works
then
	exec &> >(exec tee logfile)
else
	exec &> logfile
fi

echo starting
ls *
blah
echo finished

exec >&3 2>&4 3>&- 4>&-
sleep 1

echo tada
blah2
 
Old 08-26-2010, 09:35 AM   #22
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
There's no way you'd use only 1 since bash always sends its normal messages to fd 1 and error messages to fd 2. You'll have to recode bash if you want to do that.
 
Old 08-26-2010, 09:26 PM   #23
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,008

Original Poster
Rep: Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193
Yeah I figured I was just being greedy
 
Old 08-27-2010, 05:06 AM   #24
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
Quote:
Originally Posted by grail View Post
2. Only way to guarantee not to have unreliable output after closing descriptors is to through a sleep into the mix (not very clean but it works)
I wonder if that's really needed but perhaps just to make sure you should also close fd 1 and 2 first before redirecting them to another.
Code:
exec >&- 2>&- ...
 
Old 08-27-2010, 05:24 AM   #25
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,008

Original Poster
Rep: Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193
I added that back in and took out the sleep.

When only outputting to the logfile (ie no tee) all works fine.

When outputting to both file and stdout:

1. Screen waits for an enter to be pressed before finishing

2. tada and the final error message are not displayed at all
 
Old 08-27-2010, 05:37 AM   #26
crts
Senior Member
 
Registered: Jan 2010
Posts: 2,020

Rep: Reputation: 757Reputation: 757Reputation: 757Reputation: 757Reputation: 757Reputation: 757Reputation: 757
Quote:
Originally Posted by grail View Post
...
2. tada and the final error message are not displayed at all
That would be because commands send their output to fd1/fd2. Since they have been closed output gets nowhere. A command does not search for any other suitable file descriptors, like fd3/fd4 in this case. All the command knows is that fd1/fd2 is the pointer to STDOUT/STDERR.
 
Old 08-27-2010, 05:53 AM   #27
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,008

Original Poster
Rep: Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193
While I follow what you mean, my understanding is I have pointed fd1/fd2 back to the right places afterwards??

So line prior to last echo and non-command to raise an error is:
Code:
exec >&- 2>&- >&3 2>&4 3>&- 4>&-
Where 3 was assigned to originally point at stdout and 4 to stderr
 
Old 08-27-2010, 06:16 AM   #28
crts
Senior Member
 
Registered: Jan 2010
Posts: 2,020

Rep: Reputation: 757Reputation: 757Reputation: 757Reputation: 757Reputation: 757Reputation: 757Reputation: 757
Ok, if you do it this way then fd1/fd2 are being restored properly.
 
Old 08-27-2010, 06:32 AM   #29
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian
Posts: 8,578
Blog Entries: 31

Rep: Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208
Quote:
Originally Posted by konsolebox View Post
I wonder if that's really needed but perhaps just to make sure you should also close fd 1 and 2 first before redirecting them to another.
Code:
exec >&- 2>&- ...
Why might this be necessary?
 
Old 08-27-2010, 09:14 AM   #30
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,008

Original Poster
Rep: Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193
@catkin - hey buddy .. happy for you to suggest a better way (assuming one exists). Have a look at post #21 which shows the current evolution of the script
I am trying to use. konsolebox suggested the addition of closing descriptors 1 & 2 as a way to perhaps not require a sleep to be used so the data
would be displayed in the correct order.

I would value your input on that short script if you have any suggestions that would make it cleaner in any way?
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Scripting the kernel compile easuter Linux - Kernel 2 06-29-2007 07:23 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 12:01 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration