autoconf: File Descriptors
1
1 11.4 File Descriptors
1 =====================
1
1 Most shells, if not all (including Bash, Zsh, Ash), output traces on
1 stderr, even for subshells. This might result in undesirable content
1 if you meant to capture the standard-error output of the inner command:
1
1 $ ash -x -c '(eval "echo foo >&2") 2>stderr'
1 $ cat stderr
1 + eval echo foo >&2
1 + echo foo
1 foo
1 $ bash -x -c '(eval "echo foo >&2") 2>stderr'
1 $ cat stderr
1 + eval 'echo foo >&2'
1 ++ echo foo
1 foo
1 $ zsh -x -c '(eval "echo foo >&2") 2>stderr'
1 # Traces on startup files deleted here.
1 $ cat stderr
1 +zsh:1> eval echo foo >&2
1 +zsh:1> echo foo
1 foo
1
1 One workaround is to grep out uninteresting lines, hoping not to remove
1 good ones.
1
1 If you intend to redirect both standard error and standard output,
1 redirect standard output first. This works better with HP-UX, since
1 its shell mishandles tracing if standard error is redirected first:
1
1 $ sh -x -c ': 2>err >out'
1 + :
1 + 2> err $ cat err
1 1> out
1
1 Don't try to redirect the standard error of a command substitution.
1 It must be done _inside_ the command substitution. When running `: `cd
1 /zorglub` 2>/dev/null' expect the error message to escape, while `: `cd
1 /zorglub 2>/dev/null`' works properly.
1
1 On the other hand, some shells, such as Solaris or FreeBSD
1 `/bin/sh', warn about missing programs before performing redirections.
1 Therefore, to silently check whether a program exists, it is necessary
1 to perform redirections on a subshell or brace group:
1 $ /bin/sh -c 'nosuch 2>/dev/null'
1 nosuch: not found
1 $ /bin/sh -c '(nosuch) 2>/dev/null'
1 $ /bin/sh -c '{ nosuch; } 2>/dev/null'
1 $ bash -c 'nosuch 2>/dev/null'
1
1 FreeBSD 6.2 sh may mix the trace output lines from the statements in
1 a shell pipeline.
1
1 It is worth noting that Zsh (but not Ash nor Bash) makes it possible
1 in assignments though: `foo=`cd /zorglub` 2>/dev/null'.
1
1 Some shells, like `ash', don't recognize bi-directional redirection
1 (`<>'). And even on shells that recognize it, it is not portable to
1 use on fifos: Posix does not require read-write support for named
1 pipes, and Cygwin does not support it:
1
1 $ mkfifo fifo
1 $ exec 5<>fifo
1 $ echo hi >&5
1 bash: echo: write error: Communication error on send
1
1 Furthermore, versions of `dash' before 0.5.6 mistakenly truncate
1 regular files when using `<>':
1
1 $ echo a > file
1 $ bash -c ': 1<>file'; cat file
1 a
1 $ dash -c ': 1<>file'; cat file
1 $ rm a
1
1 When catering to old systems, don't redirect the same file descriptor
1 several times, as you are doomed to failure under Ultrix.
1
1 ULTRIX V4.4 (Rev. 69) System #31: Thu Aug 10 19:42:23 GMT 1995
1 UWS V4.4 (Rev. 11)
1 $ eval 'echo matter >fullness' >void
1 illegal io
1 $ eval '(echo matter >fullness)' >void
1 illegal io
1 $ (eval '(echo matter >fullness)') >void
1 Ambiguous output redirect.
1
1 In each case the expected result is of course `fullness' containing
1 `matter' and `void' being empty. However, this bug is probably not of
1 practical concern to modern platforms.
1
1 Solaris 10 `sh' will try to optimize away a `:' command (even if it
1 is redirected) in a loop after the first iteration, or in a shell
1 function after the first call:
1
1 $ for i in 1 2 3 ; do : >x$i; done
1 $ ls x*
1 x1
1 $ f () { : >$1; }; f y1; f y2; f y3;
1 $ ls y*
1 y1
1
1 As a workaround, `echo' or `eval' can be used.
1
1 Don't rely on file descriptors 0, 1, and 2 remaining closed in a
1 subsidiary program. If any of these descriptors is closed, the
1 operating system may open an unspecified file for the descriptor in the
1 new process image. Posix 2008 says this may be done only if the
1 subsidiary program is set-user-ID or set-group-ID, but HP-UX 11.23 does
1 it even for ordinary programs, and the next version of Posix will allow
1 HP-UX behavior.
1
1 If you want a file descriptor above 2 to be inherited into a child
1 process, then you must use redirections specific to that command or a
1 containing subshell or command group, rather than relying on `exec' in
1 the shell. In `ksh' as well as HP-UX `sh', file descriptors above 2
1 which are opened using `exec N>file' are closed by a subsequent `exec'
1 (such as that involved in the fork-and-exec which runs a program or
1 script):
1
1 $ echo 'echo hello >&5' >k
1 $ /bin/sh -c 'exec 5>t; ksh ./k; exec 5>&-; cat t
1 hello
1 $ bash -c 'exec 5>t; ksh ./k; exec 5>&-; cat t
1 hello
1 $ ksh -c 'exec 5>t; ksh ./k; exec 5>&-; cat t
1 ./k[1]: 5: cannot open [Bad file number]
1 $ ksh -c '(ksh ./k) 5>t; cat t'
1 hello
1 $ ksh -c '{ ksh ./k; } 5>t; cat t'
1 hello
1 $ ksh -c '5>t ksh ./k; cat t
1 hello
1
1 Don't rely on duplicating a closed file descriptor to cause an
1 error. With Solaris `/bin/sh', failed duplication is silently ignored,
1 which can cause unintended leaks to the original file descriptor. In
1 this example, observe the leak to standard output:
1
1 $ bash -c 'echo hi >&3' 3>&-; echo $?
1 bash: 3: Bad file descriptor
1 1
1 $ /bin/sh -c 'echo hi >&3' 3>&-; echo $?
1 hi
1 0
1
1 Fortunately, an attempt to close an already closed file descriptor
1 will portably succeed. Likewise, it is safe to use either style of
1 `N<&-' or `N>&-' for closing a file descriptor, even if it doesn't
1 match the read/write mode that the file descriptor was opened with.
1
1 DOS variants cannot rename or remove open files, such as in `mv foo
1 bar >foo' or `rm foo >foo', even though this is perfectly portable
1 among Posix hosts.
1
1 A few ancient systems reserved some file descriptors. By convention,
1 file descriptor 3 was opened to `/dev/tty' when you logged into Eighth
1 Edition (1985) through Tenth Edition Unix (1989). File descriptor 4
1 had a special use on the Stardent/Kubota Titan (circa 1990), though we
1 don't now remember what it was. Both these systems are obsolete, so
1 it's now safe to treat file descriptors 3 and 4 like any other file
1 descriptors.
1
1 On the other hand, you can't portably use multi-digit file
1 descriptors. Solaris `ksh' doesn't understand any file descriptor
1 larger than `9':
1
1 $ bash -c 'exec 10>&-'; echo $?
1 0
1 $ ksh -c 'exec 9>&-'; echo $?
1 0
1 $ ksh -c 'exec 10>&-'; echo $?
1 ksh[1]: exec: 10: not found
1 127
1