Re: bash redirection stdout and stderr - pipeline command causes subshell execution

From: Netocrat (netocrat_at_dodo.com.au)
Date: 09/04/05

  • Next message: zipporuni: "Automating password change"
    Date: Sun, 04 Sep 2005 13:18:17 +1000
    
    

    On Fri, 02 Sep 2005 23:05:50 +0100, S. Anthony Sequeira wrote:

    > Hi,
    >
    > Hope I piqued your interest with the subject.

    You did. I've just become aware of this issue myself.

    > I will try to be clear.
    >
    > I have a function which executes several commands.
    >
    > It is called thus:
    >
    > { function 3>&1 1>&2 2>&3 | tee function.err } &> function.log
    >
    > This works fine, inasmuch it produces a logfile with just the errors,
    > and another with both stdout and stderr interleaved, for further
    > investigation of anything in the error log.
    >
    > The problem is when one or more of the commands sets a variable which
    > should be available further down the script, or when a cd is done within
    > the function, again required later.
    >
    > My research (man pages and google) indicate that a pipe symbol causes
    > commands to be executed in a subshell. This causes any environmental
    > alterations in the function not to be propagated to the rest of the
    > script.

    Bash's manpage documents this behaviour for "simple command[s] other than
    a builtin or shell function" and also "[c]ommand substitution, commands
    grouped with parentheses, and asynchronous commands ... Builtin commands
    that are invoked as part of a pipeline are also executed in a subshell
    environment."

    This is pretty similar to the POSIX shell spec at
    http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_12
    which is not surprising given that bash is a POSIX shell.

    However the POSIX spec adds:
    "Additionally, each command of a multi-command pipeline is in a subshell
    environment; as an extension, however, any or all commands in a pipeline
    may be executed in the current environment."

    A little ambiguous for a specification... and yes, bash chooses not to
    offer this extension as you have discovered.

    This leads to undesirable inconsistency. The fish shell deals with this
    issue by never forking a new shell instance, thus ensuring consistency and
    slightly better (but probably unnoticably) execution times. If you want
    a distinct subshell environment in fish, you must explicitly run a new
    shell interpreter.

    You might find fish useful in your situation, with the caveat that
    redirecting fds other than 0, 1, 2 is somewhat broken in the current
    release. Also redirection currently works at pipeline level rather than
    individual process level, so you'd have to wrap the function call
    redirections in another block, something like:
    { { function 3>&1 1>&2 2>&3 } | tee function.err } &> function.log
    except that the fish syntax is slightly different - it doesn't support
    braces so you'd have to use an "if true" block. There's discussion of
    adding a block operator.

    Even though written after the standard, fish deviates from POSIX in many
    other ways, largely to improve and simplify shell syntax from the author's
    point of view; his philosophy is that for portable POSIX scripting bash is
    available and therefore fish is free to improve on POSIX's syntax. Its
    focus is on user-friendliness and interactive use and it contains some
    neat ideas with development ongoing. One useful addition to fish is
    variable scoping; scope is local by default.

    > I have been attempting to find a construct that will duplicate the
    > logging facility, without operating in a subshell, in vain. I can place
    > any such commands outside the function call, but this is not ideal, as I
    > lose the logging.

    You could pass the logging filenames into the function and perform the
    redirections and tee on each command within the function, but that would
    be pretty inconvenient. Perhaps other shells (ksh, zsh) have chosen not
    to fork in this situation and you could use one of them instead, but I
    suspect that they would do the same.

    > Any ideas please?

    Well you needn't perform the environment-changing commands within the
    function; in your later post you say that logging would be lost in that
    case, but what logging do you want to perform on changing a directory or
    setting a variable? And if you do need to log such things, what's
    stopping you?

    > Cheers.

    -- 
    http://members.dodo.com.au/~netocrat
    

  • Next message: zipporuni: "Automating password change"

    Relevant Pages

    • Re: PYTHONPATH
      ... The error indicates the shell tried to execute a program named '1' and couldn't find one. ... Arthimetic expressions generally have to be wrapped in ) in bash: ... non-interactive shell with the --login option, it first reads and executes ... commands from the file /etc/profile, ...
      (comp.lang.python)
    • Re: process /etc/profile Redhat
      ... any need to reboot in relation to /etc/profile. ... as a non-interactive shell with the --login option, ... it first reads and executes commands from the file ...
      (comp.os.linux.misc)
    • Re: (still) Re: trouble with Runtime.getRuntime().exec(cmd) on Linux
      ... When you enter commands at a command prompt in Unix, ... sending the commands to a shell program. ... The shell interprets the commands and executes processes ... If you would like to put your commands in a script, ...
      (comp.lang.java)
    • Re: Quick help
      ... shell variable...Usually Path doesn't include your working directory... ... if it executes you could think of extending PATH by typeing ... /standard/ commands. ... specific directory, then you need to specify that path, as in ...
      (comp.unix.questions)
    • Re: Redirection issue
      ... 1- execute input commands from standard input, ... code to implement the redirection it does not work anymore. ... And it's not good shell behavior to echo commands anyway. ...
      (comp.lang.c)