It is currently Sat, 26 Nov 2022 06:40:05 GMT



 
Author Message
 initializing a variable and simultaneously keeping terminal output
Hi everybody,

I want to put the result (standard output and error) of a command in a
variable, so as to be able to process it. This command is interactive (can
ask to type yes, or no, for example).

a="`command 2>&1`"

But I want to have simultaneouly the display of the interactive command in
the terminal (so as to be able to read what the command asks, and act
consequently, for example typing yes or no). How can I do that?

For the time being, I do:

command 2>&1 | tee foo

And then I analyse the content of the file "foo".
But it is less pretty.

Thanks in advance,

Julien
--
"Allez, Monsieur, allez, et la foi vous viendra." (D'Alembert).



 Wed, 03 Oct 2007 17:36:20 GMT   
 initializing a variable and simultaneously keeping terminal output
2005-04-16, 11:36(+02), Julien SCORDIA:
[...]

If your system supports /dev/fd/<n>,

exec 3>&1
a=`command 2>&1 3>&- | tee /dev/fd/3`
exec 3>&-

Or with zsh

setopt multios
{ a=$(command >&1 >&3 3>&- 2>&1);} 3>&1

In both cases, beware that "command" internal buffering behavior
may be affected by the fact that stdout and stderr are a pipe and
no longer terminals.

--
Stphane



 Wed, 03 Oct 2007 18:45:14 GMT   
 initializing a variable and simultaneously keeping terminal output
On comp.unix.shell, in <4260dc92$0$17364$626a1...@news.free.fr>,

Julien,

That variable is going to be a mess, as you say. If I
am following you, just let the stdout and stderr print
to the screen and use a case menu in a while loop.

#!/bin/sh

command

while true
do

echo
echo
echo "instructions"
echo
echo
echo "[Y] do this thing"
echo
echo "[N] do that thing"
echo
echo
read let
case "$let" in
[yY] ) command ; break ;;
[nN] ) other command ; break ;;
* ) echo "no such option -- try again; continue  ;;
esac
done

AC



 Wed, 03 Oct 2007 18:59:24 GMT   
 initializing a variable and simultaneously keeping terminal output

Thanks Stphane for your answer.
It works fine, but I wonder why not just using:

a=`command 2>&1 | tee /dev/fd/2`

I'm rather new to the subtilities of redirection, there are surely things
that I do not see.
Thanks in advance.
Julien
--
"Allez, Monsieur, allez, et la foi vous viendra." (D'Alembert).



 Thu, 04 Oct 2007 00:37:43 GMT   
 initializing a variable and simultaneously keeping terminal output
2005-04-16, 18:37(+02), Julien SCORDIA:
[...]

Because that redirects command's output to your script stderr,
not to its stdout.

For instance

yourscript | grep -v 'unwanted'

won't filter yourscript output, as the output will go to stderr.

and there's no reason a priori to consider command's output as
errors.

Note that that exec thing is not costing anything, in most
shells (the Bourne shell is the only exception I know, but you
find it only on Solaris /bin/sh nowadays), you can even write it
as:

{ a=`command 2>&1 3>&- | tee /dev/fd/3`; } 3>&1

--
Stphane



 Thu, 04 Oct 2007 01:08:48 GMT   
 initializing a variable and simultaneously keeping terminal output
On Sat, 16 Apr 2005 11:36:20 +0200, Julien SCORDIA
I don't know if this is any prettier:
a=`command 2>&1 | tee /dev/tty`

--
"I deleted a file from my PC last week and I have just realized that I
need it. If I turn my system clock back two weeks will I have my file
back again?"



 Wed, 03 Oct 2007 18:53:12 GMT   
 initializing a variable and simultaneously keeping terminal output

(your example)

Stphane, I tried a lot of command lines since my last post in this thread.
I have improved my shell knowledge (difference between (...) and { ...; }
for example). But redirection problems are not easy (for me) (as quoting, a
very complex subject for me, I have spent hours on this).
I have two questions:

1/ The first, I read the note in the bash manual:

##########
Note that the order of redirections is significant.  For  example,  the
command
   ls > dirlist 2>&1
directs  both  standard  output and standard error to the file dirlist,
while the command
   ls 2>&1 > dirlist
directs only the standard output to file dirlist, because the  standard
error  was duplicated as standard output before the standard output was
redirected to dirlist.
##########

What is the problem when standard error is duplicated before standard
output? I could understand that we put 2 in 1, and then 1 in dirlist. What
is wrong? I am very frustrated..

2/ I want to make a script that do a tutorial: the goal is to display shell
commands and their results with only one call, thanks to the tutorial_gen
function (see below). Here it fails for exec 3>&1, why?
How could I improve this script?

Thanks in advance...

#!/bin/sh

tutorial_gen()
{
echo
"#############################################################################"
for i in "$@";do
    echo $ $i
    if [ `echo $i | sed "s/\(.\).*/\1/"` != "#" ];then_
._______$i
    fi
done
echo
"#############################################################################"

tutorial_gen \
"# List all directories" \
"ls -d" \
"# For all the script, /dev/fd/3 points to the script standard output" \
'exec 3>&1'
--
"Allez, Monsieur, allez, et la foi vous viendra." (D'Alembert).



 Thu, 04 Oct 2007 05:56:35 GMT   
 initializing a variable and simultaneously keeping terminal output
2005-04-16, 23:56(+02), Julien SCORDIA:

In:

ls 2>&1 > dirlist

the shell does:

dup2(2, 1)

Which means that from now on every write to fd 2 (to stderr)
will go to the resource that was opened on fd 1.

In fd = open("dirlist")

The system creates a "writing channel" to that file (a file
handle) and then associates the file descriptor returned by open
and stored into fd with it.

dup2(fd, other-fd), or other-fd>&fd and other-fd is also
associated with that channel.

So you understand that if you do first dup2(2, 1), and then fd =
open("dirlist"); dup2(fd, 1) fd 2 will be associated with the
"channel" that was initially associated with fd 1 (whatever it
is) and fd 2 will be associates with the "writing channel" to
dirlist.

- Show quoted text -

In:

i='exec 3>&1'
$i

The shell splits the content of the variable i on spaces, which
in that exemple results in two words "exec" and "3>&1" which is
a mechanism called "word splitting" that has nothing to do with
the normal shell parsing (what is done when you type "exec 3>&1"
at the shell prompt), then it performs what is called filename
generation (it expands "*" into the list of files in the current
directory for instance), in that example, it does nothing more
so the words are still "exec" and "3>&1".

In that context those words are taken as arguments (not as a shell
tokens or whatever, as if you had typed "exec 3>&1"), because
the shell has already parsed $i as being a simple command line
before expanding $i, as otherwise that would mean that in cases
like:

i='foo; rm -rf -- "$HOME"'
echo $i

your HOME directory would be removed.

So, "exec" is the 0th argument to the "exec" command (which the
shell will identify as the "exec" shell special builtin), and
"3>&1" is an argument passed to exec. And when exec is passed
arguments, it takes them as a command to run without forking.
So exec will try to execute a command named "3>&1" and will
probably miserably fail.

When you type "exec 3>&1" at the prompt, it's another matter.

The shell identifies it as a simple command with a redirection.

It will run "exec" with no argument (which tells the shell not
to fork) and perform the redirection (dup2(1, 3))

Now, you can do:

i="exec 3>&1"
eval "$i"

which tells the shell to evaluate eval's first argument (which
will be the content of $i) as a command line.

Or you could even do:

i='eval,exec 3>&1'
IFS=','
set -f
$i

IFS=, tells the shell to do the word splitting on comas instead
of on blanks.

set -f tells the shell to disable that annoying feature that is
filename generaton.

$i is a simple command whose arguments are the result of the
expansion of $i (which involves word splitting (and no filename
generation as we disabled it), which will be "eval" and
"exec 3>&1". Then eval will evaluate "exec 3>&1" as a command
line.

tutorial_gen() {
  for i
  do
    case $i in
      "#"*)
        printf '%s\n' "$i"
      ;;
      *)
        printf '$ %s\n' "$i"
        eval "$i"
      ;;
    esac
  done

tutorial_gen \
  '# list the current directory' \
  'ls -d' \
  '# redirect fd 3 to the same channel as fd 1' \
  'exec 3>&1'

--
Stphane



 Thu, 04 Oct 2007 06:56:17 GMT   
 initializing a variable and simultaneously keeping terminal output

Thanks a lot Stphane!

It is dup2(1,2) (I have looked in the bash sources), but you know it of
course, it is surely the result of a moment of inattention (you were right
below).

[...]
Thanks to your help, I have understood the difference!

[your explanation]

Thanks a lot. I feel ashamed, because I had read the guide to Unix Shell
Quoting of Uwe Waldmann:

http://www.mpi-sb.mpg.de/~uwe/lehre/unixffb/quoting-guide.html

That allowed me to understand a lot of things.
But it is true that the analysis of shell input interpretation must be
performed in a very precise way, very carefully. I should have done so.

Thanks a lot.

Julien
--
"Allez, Monsieur, allez, et la foi vous viendra." (D'Alembert).



 Thu, 04 Oct 2007 17:18:45 GMT   
 initializing a variable and simultaneously keeping terminal output
2005-04-17, 11:18(+02), Julien SCORDIA:
[...]

Yes, you're right, it should have been
dup2(1, 2);

That part is correct and is the result of dup2(1, 2).

--
Stphane



 Thu, 04 Oct 2007 17:28:54 GMT   
 initializing a variable and simultaneously keeping terminal output
2005-04-17, 11:18(+02), Julien SCORDIA:
[...]
[...]

Which was a very good idea. Everyone should read and understand
that document before writing any single shell script.

--
Stphane



 Thu, 04 Oct 2007 17:36:40 GMT   
 
   [ 11 post ] 

Similar Threads

1. Can sound cards simultaneously handle input and output?

2. writing simultaneously to std output and a file

3. please help...question about how to get output of two commands simultaneously

4. Formattet output inside variable / line brak inside variable

5. capturing an output variable into a shell variable

6. variable output/variable input

7. initialize the global variables in .so files

8. Initializing ksh variables

9. Initializing variables


 
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software