77

Occasionally I need to specify a "path-equivalent" of one of the standard IO streams (stdin, stdout, stderr). Since 99% of the time I work with Linux, I just prepend /dev/ to get /dev/stdin, etc., and this "seems to do the right thing". But, for one thing, I've always been uneasy about such a rationale (because, of course, "it seems to work" until it doesn't). Furthermore, I have no good sense for how portable this maneuver is.

So I have a few questions:

  1. In the context of Linux, is it safe (yes/no) to equate stdin, stdout, and stderr with /dev/stdin, /dev/stdout, and /dev/stderr?

  2. More generally, is this equivalence "adequately portable"?

I could not find any POSIX references.

Ciro Santilli OurBigBook.com
  • 18,092
  • 4
  • 117
  • 102
kjo
  • 15,339
  • 25
  • 73
  • 114

5 Answers5

46

It's been available on Linux back into its prehistory. It is not POSIX, although many actual shells (including AT&T ksh and bash) will simulate it if it's not present in the OS; note that this simulation only works at the shell level (i.e. redirection or command line parameter, not as explicit argument to e.g. open()). That said, it should be available on most commercial Unix systems, one way or another (sometimes it's spelled /dev/fd/N for various integers N, but most systems with that will provide symlinks as Linux and *BSD do).

geekosaur
  • 32,047
  • 16
    Indeed, /dev/std{in,out,err} are specifically listed as not part of the POSIX.1-2008 standard. – jw013 Apr 13 '12 at 23:05
  • 2
    It appears that ash doesn't support /dev/stdout in initrd (http://git.razvi.ro/?p=openwrt.org%2Fopenwrt.git&a=commit&h=c20510da95c90df8cb4581c7bbc85d6eb9dc218f) – CMCDragonkai Feb 13 '16 at 05:48
  • @CMCDragonkai: That's not a /dev/stdout that can be handled by the shell, and what did you expect of initrd? It's missing most nicities in order to make it as small as practical. – Joshua Nov 01 '16 at 16:04
  • 2
    In 2021 still explicitly listed as not part of POSIX in "P1003.1™-202x, Draft 2.1, August 2021" (the current POSIX draft). – pabouk - Ukraine stay strong Nov 29 '21 at 09:44
27

the /dev/std{in,out,err} files are normally just symlinks to /proc/self/fd/{0,1,2} (respectively). As such theres nothing gained over using methods that are POSIX defined.

If you want to be POSIX compliant, the best way to do this is to use output redirection. Shell output redirection is defined in the POSIX standard. Additionally the STDIN, STDOUT, STDERR file descriptor numbers are also part of POSIX.
In short, things like >&2 are guaranteed to work.

One important thing to note though is that usage of STDIN, STDOUT, and STDERR is subjective to how the program was started. If the program was started with file descriptor 1 being an open handle to a file, then your program just has to accept it. Even if you were to have the program open up /dev/stdout, all it would do is open up file descriptor 1 which is still going to point to that file.
If this is what youre trying to get around, you need to open the TTY directly. Normally, without any redirection going on, STDIN, STDOUT, and STDERR are all just open file descriptors pointing to the same TTY. There is absolutely nothing more to it than that.

phemmer
  • 71,831
7

POSIX 7 says they are extensions.

Base Definitions, Section 2.1.1 Requirements:

The system may provide non-standard extensions. These are features not required by POSIX.1-2008 and may include, but are not limited to:

[...]

  • Additional character special files with special properties (for example,  /dev/stdin, /dev/stdout,  and  /dev/stderr)

Found by grepping the POSIX HTML: Where is the list of the POSIX C API functions?

Also quite weirdly, the uuencode tool gives /dev/stdout a magic effect:

Specifying a decode_pathname operand of /dev/stdout shall indicate that uudecode is to use standard output.

The Linux kernel documentation says all systems should have it.

https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/devices.rst

Compulsory links
These links should exist on all systems:
/dev/fd       /proc/self/fd   symbolic   File descriptors
/dev/stdin    fd/0            symbolic   stdin file descriptor
/dev/stdout   fd/1            symbolic   stdout file descriptor
/dev/stderr   fd/2            symbolic   stderr file descriptor

I could not, however, find where those symlinks are created in the kernel (distro provided?).

Ciro Santilli OurBigBook.com
  • 18,092
  • 4
  • 117
  • 102
6

/dev/{stdout,stdin,stderr} work in Bash on these platforms:

Linux debian-ppc 3.16.0-4-powerpc #1 Debian 3.16.7-ckt25-1 (2016-03-06) ppc GNU/Linux
HP-UX hpux-ia6 B.11.31 U ia64 0107668277 unlimited-user license
AIX aix7 1 7 000ACFDE4C00
FreeBSD freebsd.polarhome.com 10.0-RELEASE-p7 FreeBSD 10.0-RELEASE-p7 #0: Tue Jul  8 06:37:44 UTC 2014     root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC  amd64
HP-UX hpux64 B.11.11 U 9000/785 2000587908 unlimited-user license
Darwin macosx 11.4.2 Darwin Kernel Version 11.4.2: Thu Aug 23 16:26:45 PDT 2012; root:xnu-1699.32.7~1/RELEASE_I386 i386
GNU hurd 0.7 GNU-Mach 1.6-486/Hurd-0.7 i686-AT386 GNU
Linux mandriva.polarhome.com 2.6.33.7-desktop-2mnb #1 SMP Mon Sep 20 18:19:20 UTC 2010 x86_64 x86_64 x86_64 GNU/Linux
SunOS openindiana 5.11 oi_148 i86pc i386 i86pc
MirBSD miros.polarhome.com 10 Kv#10uAF-20110818 GENERIC#1330 i386
Linux pidora 3.12.23-2.20140626git25673c3.rpfr20.armv6hl.bcm2708 #1 PREEMPT Fri Jul 4 16:06:10 EDT 2014 armv6l armv6l armv6l GNU/Linux
QNX qnx 6.5.0 2010/07/09-14:44:03EDT x86pc x86
NetBSD netbsd.polarhome.com 6.1.3 NetBSD 6.1.3 (GENERIC) i386
OpenBSD openbsd.polarhome.com 4.9 GENERIC#671 i386
Linux raspbian 3.18.7+ #755 PREEMPT Thu Feb 12 17:14:31 GMT 2015 armv6l GNU/Linux
SCO_SV scosysv 5 6.0.0 i386
Linux redhat.polarhome.com 3.17.4-301.fc21.x86_64 #1 SMP Thu Nov 27 19:09:10 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
SunOS solaris-x86 5.11 11.3 i86pc i386 i86pc
Linux suse 3.4.63-2.44-desktop #1 SMP PREEMPT Wed Oct 2 11:18:32 UTC 2013 (d91a619) x86_64 x86_64 x86_64 GNU/Linux
SunOS solaris 5.10 Generic_147147-26 sun4u sparc SUNW,Sun-Fire-V210
Linux ubuntu 3.13.0-85-generic #129-Ubuntu SMP Thu Mar 17 20:50:15 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
UnixWare unixware 5 7.1.4 i386 x86at SCO UNIX_SVR5
OSF1 tru64.polarhome.com V5.1 2650 alpha
Linux debian 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt20-1+deb8u2 (2016-01-02) x86_64 GNU/Linux

But fails in csh on these:

HP-UX hpux-ia6 B.11.31 U ia64 0107668277 unlimited-user license
Linux centos.polarhome.com 2.6.18-409.el5 #1 SMP Tue Mar 15 18:13:50 EDT 2016 x86_64 x86_64 x86_64 GNU/Linux
HP-UX hpux64 B.11.11 U 9000/785 2000587908 unlimited-user license
AIX aix7 1 7 000ACFDE4C00
SCO_SV scosysv 5 6.0.0 i386
SunOS solaris-x86 5.11 11.3 i86pc i386 i86pc
SunOS openindiana 5.11 oi_148 i86pc i386 i86pc
SunOS solaris 5.10 Generic_147147-26 sun4u sparc SUNW,Sun-Fire-V210
UnixWare unixware 5 7.1.4 i386 x86at SCO UNIX_SVR5
OSF1 tru64.polarhome.com V5.1 2650 alpha
Ole Tange
  • 35,514
  • 10
    What was your test case? bash is special as it can be compiled to handle /dev/fd/x by itself for redirections on systems that don't have /dev/fd – Stéphane Chazelas Apr 22 '16 at 16:14
  • @StéphaneChazelas I've downvoted just because I can see this being misleading without that clarification (no offense to Ole). – Evan Carroll Apr 13 '18 at 19:11
3

One issue with /dev/stdout and friends is that you may not have permission to write to them in certain circumstances. For example, I've encountered this when invoking scripts from Nix, and I imagine similar tools which run scripts in jails/sandboxes/containers/VMs/etc. may encounter similar issues.

Using syntax like 1>&2 worked in these cases and, since I knew I'd be running in Bash, I could use process substitution for commands which expect filenames.

Warbo
  • 281