All four of /dev/fd/0
, /dev/stdin
, /proc/self/fd/0
and /dev/pts/2
are file names, as are /////dev/../dev/fd//0
, /bin/sh
, /etc/fstab
, /fioejfoeijf
, etc. All but that last example are likely to be the name of an existing file on your machine. A file name is a string that can designate a file on your filesystem; under Linux, any string that does not contain a null byte and that is at most 4096 bytes long is a valid file name. Many of these names are equivalent, e.g. /bin/sh
is equivalent to ///bin/sh
, /bin/../bin/sh
(assuming /bin
is an existing directory), etc. All the examples I've given so far are absolute file names; there are also relative file names, which do not begin with a /
and whose meaning depends on the current directory.
The terminology surrounding file names isn't universal; sometimes “file name” means a full path to a file, and sometimes it means the name of a directory entry. The POSIX terminology is “filename” or “pathname component” for the name of a directory entry, and “pathname” for a full path.
A file descriptor designates an open file in a particular process. The kernel maintains a table of file descriptors for each process. Each entry in the file descriptor table indicates what to do if the process requests reading, writing and other operations on the file descriptor.
File descriptors may correspond to a file and have an associated name, but not all of them do. For those that do, the file may be a regular file, a directory, a device file or a named pipe (also called FIFO) (the kind created by mkfifo
); some systems have further possibilities such as Unix sockets and doors. Examples of file descriptors that don't have an associated named file include pipes (the kind created by the pipe
system call) and networking sockets.
/dev/fd/0
, /dev/stdin
and /proc/self/fd/0
are file names (all equivalent) with a peculiar meaning: they all designate whichever file is currently accessed via file descriptor 0. When a process opens these, the kernel copies the entry with index 0 in the file descriptor table to a new descriptor. Opening any of these files is equivalent to calling dup(0)
. The named files are a way to indirectly get a process to use one of its already-open files rather than open a new file; they are mostly useful to pass on a program's command line, where the program expects the name of a file to open.
cat <&3
does exactly what it's supposed to do, namely read from the file until it reaches the end of the file. When you call it, the file position on the file descriptor is where you last left it, namely, at the end of the file. (There's a single file position, not separate ones for reading and for writing.)
cat /proc/$$/fd/3
doesn't do the same thing as cat <&3
: it opens the same file on a different descriptor. Since each file descriptor has its own position, and the position is set to 0 when opening a file for reading, this command prints the whole file and doesn't affect the script.
If you want to read back what you wrote, you need to either reopen the file or rewind the file descriptor (i.e. set its position to 0). There's no built-in way to do either in a POSIX shell nor in most sh implementations (there is one in ksh93). There is only one utility that can seek: dd
, but it can only seek forward. (There are other utilities that may skip forward but that doesn't help.)
I think the only portable solution is to remember the file name and open it as many times as necessary. Note that if the file isn't a regular file, you might not be able to seek backwards anyway.
Best Answer
63
on a typical Linux box.stdlog
, but it's rarely used (I believe I never saw one).man bash
REDIRECTION.