Skip to main content
added 694 characters in body
Source Link
Stéphane Chazelas
  • 584.6k
  • 96
  • 1.1k
  • 1.7k

Also note that:

echo hello | cmd /dev/stdin # or /dev/fd/0, /proc/self/fd/0²

Doesn't work with ksh93 on Linux, because there, ksh93's | uses socketpairs instead of pipes³ and on Linux (and Cygwin), contrary to other systems, opening /dev/stdin is not like dup(0), it opens the same file as open on stdin, and you can't open() a socket.

More reading in connected Q&As here:

¹ very few these days and there are probably far more systems without bash than without /dev/fd/x

² except for those commands such as gawk that treat or can treat /dev/stdin as meaning stdin by themselves without actually opening the file in the same was as for -.

³ as Linux' pipe implementation doesn't let you peek at the contents which ksh93 needs to perform some (dubious) optimisations.

More reading in connected Q&As here:

¹ very few these days and there are probably far more systems without bash than without /dev/fd/x

Also note that:

echo hello | cmd /dev/stdin # or /dev/fd/0, /proc/self/fd/0²

Doesn't work with ksh93 on Linux, because there, ksh93's | uses socketpairs instead of pipes³ and on Linux (and Cygwin), contrary to other systems, opening /dev/stdin is not like dup(0), it opens the same file as open on stdin, and you can't open() a socket.

More reading in connected Q&As here:

¹ very few these days and there are probably far more systems without bash than without /dev/fd/x

² except for those commands such as gawk that treat or can treat /dev/stdin as meaning stdin by themselves without actually opening the file in the same was as for -.

³ as Linux' pipe implementation doesn't let you peek at the contents which ksh93 needs to perform some (dubious) optimisations.

added 1353 characters in body
Source Link
Stéphane Chazelas
  • 584.6k
  • 96
  • 1.1k
  • 1.7k

Since we mention portability though, note that in zsh, you need:

echo hello | { diff <(echo ok) <(cat); }

For the stdin of cat to also be the pipe from echo.

More reading in connected Q&As here:

Since we mention portability though, note that in zsh, you need:

echo hello | { diff <(echo ok) <(cat); }

For the stdin of cat to also be the pipe from echo.

More reading in connected Q&As here:

added 1353 characters in body
Source Link
Stéphane Chazelas
  • 584.6k
  • 96
  • 1.1k
  • 1.7k

diff -u <(echo foo) <(cat) doesn't work in an interactive bash because commands in process substitution are not put in the foreground so can't read from the terminal device. Like in cat & where cat is also run in background (not in the foreground process group of the terminal device), the process running cat is suspended with a SIGTTIN signal as soon as it tries to read from its controlling terminal.

echo hello | diff -u <(echo ok ) <(cat)' works because the whole pipeline made of two subshells is in foreground, and anyway cat is reading from the pipe, not the terminal. The process substitutionsubstitutions end up being in foreground because they were started by the subshell (the second component of that pipeline) that is in foreground.

bash-5.0$ diff -u <(echo ok ) <(ps -o pid,ppid,pgid,args)
--- /dev/fd/63  2021-11-12 22:39:41.985207894 +0000
+++ /dev/fd/62  2021-11-12 22:39:41.985207894 +0000
@@ -1 +1,6 @@
-ok
+    PID    PPID    PGID COMMAND
+   9779    9772    9779 /bin/zsh
+1957388    9779 1957388 bash --norc
+1958861 1957388 1957388 bash --norc
+1958862 1957388 1958862 diff -u /dev/fd/63 /dev/fd/62
+1958863 1958861 1957388 ps -o pid,ppid,pgid,args
bash-5.0$ (diff -u <(echo ok ) <(ps -o pid,ppid,pgid,args))
--- /dev/fd/63  2021-11-12 22:42:04.761112701 +0000
+++ /dev/fd/62  2021-11-12 22:42:04.761112701 +0000
@@ -1 +1,6 @@
-ok
+    PID    PPID    PGID COMMAND
+1960605    9772 1960605 /bin/zsh
+1960612 1960605 1960612 bash --norc
+1960757 1960612 1960757 diff -u /dev/fd/63 /dev/fd/62
+1960759 1960757 1960757 bash --norc
+1960760 1960759 1960757 ps -o pid,ppid,pgid,args

It's back to being OK as then we start a whole subshell in foreground.

So the easy work around here is to run the pipeline in a subshell.

In any case, again, that only applies to interactive shells (where terminal job control is being performed) and when stdin is the controlling terminal of the session.

In scripts (and you generally only care about portability in scripts), there's no problem with diff -u <(echo ok) <(cat) even when stdin is a terminal as the shell is non-interactive and doesn't do job control.

That cat however does nothing useful, it's the same UUOC as in:

cat | diff -u <(echo ok) -

Or

cat | diff -u <(echo ok) /dev/stdin

On systems that don't support /dev/fd/x / /dev/stdin¹, for commands which unlike diff, don't support - to specify stdin, <(cat) in bash or zsh (but not in ksh versions prior to ksh93u where that feature comes from) uses a temporary named pipe instead, so diff -u <(echo ok) <(cat) will still work on those systems.


¹ very few these days and there are probably far more systems without bash than without /dev/fd/x

diff -u <(echo foo) <(cat) doesn't work in an interactive bash because commands in process substitution are not put in the foreground so can't read from the terminal.

echo hello | diff -u <(echo ok ) <(cat)' works because the whole pipeline made of two subshells is in foreground, and anyway cat is reading from the pipe, not the terminal. The process substitution end up being in foreground because they were started by the subshell that is in foreground.

bash-5.0$ diff -u <(echo ok ) <(ps -o pid,ppid,pgid,args)
--- /dev/fd/63  2021-11-12 22:39:41.985207894 +0000
+++ /dev/fd/62  2021-11-12 22:39:41.985207894 +0000
@@ -1 +1,6 @@
-ok
+    PID    PPID    PGID COMMAND
+   9779    9772    9779 /bin/zsh
+1957388    9779 1957388 bash --norc
+1958861 1957388 1957388 bash --norc
+1958862 1957388 1958862 diff -u /dev/fd/63 /dev/fd/62
+1958863 1958861 1957388 ps -o pid,ppid,pgid,args
bash-5.0$ (diff -u <(echo ok ) <(ps -o pid,ppid,pgid,args))
--- /dev/fd/63  2021-11-12 22:42:04.761112701 +0000
+++ /dev/fd/62  2021-11-12 22:42:04.761112701 +0000
@@ -1 +1,6 @@
-ok
+    PID    PPID    PGID COMMAND
+1960605    9772 1960605 /bin/zsh
+1960612 1960605 1960612 bash --norc
+1960757 1960612 1960757 diff -u /dev/fd/63 /dev/fd/62
+1960759 1960757 1960757 bash --norc
+1960760 1960759 1960757 ps -o pid,ppid,pgid,args

It's back to being OK as then we start a whole subshell in foreground.

diff -u <(echo foo) <(cat) doesn't work in an interactive bash because commands in process substitution are not put in the foreground so can't read from the terminal device. Like in cat & where cat is also run in background (not in the foreground process group of the terminal device), the process running cat is suspended with a SIGTTIN signal as soon as it tries to read from its controlling terminal.

echo hello | diff -u <(echo ok) <(cat) works because the whole pipeline made of two subshells is in foreground, and anyway cat is reading from the pipe, not the terminal. The process substitutions end up being in foreground because they were started by the subshell (the second component of that pipeline) that is in foreground.

bash-5.0$ diff -u <(echo ok) <(ps -o pid,ppid,pgid,args)
--- /dev/fd/63  2021-11-12 22:39:41.985207894 +0000
+++ /dev/fd/62  2021-11-12 22:39:41.985207894 +0000
@@ -1 +1,6 @@
-ok
+    PID    PPID    PGID COMMAND
+   9779    9772    9779 /bin/zsh
+1957388    9779 1957388 bash --norc
+1958861 1957388 1957388 bash --norc
+1958862 1957388 1958862 diff -u /dev/fd/63 /dev/fd/62
+1958863 1958861 1957388 ps -o pid,ppid,pgid,args
bash-5.0$ (diff -u <(echo ok) <(ps -o pid,ppid,pgid,args))
--- /dev/fd/63  2021-11-12 22:42:04.761112701 +0000
+++ /dev/fd/62  2021-11-12 22:42:04.761112701 +0000
@@ -1 +1,6 @@
-ok
+    PID    PPID    PGID COMMAND
+1960605    9772 1960605 /bin/zsh
+1960612 1960605 1960612 bash --norc
+1960757 1960612 1960757 diff -u /dev/fd/63 /dev/fd/62
+1960759 1960757 1960757 bash --norc
+1960760 1960759 1960757 ps -o pid,ppid,pgid,args

It's back to being OK as then we start a whole subshell in foreground.

So the easy work around here is to run the pipeline in a subshell.

In any case, again, that only applies to interactive shells (where terminal job control is being performed) and when stdin is the controlling terminal of the session.

In scripts (and you generally only care about portability in scripts), there's no problem with diff -u <(echo ok) <(cat) even when stdin is a terminal as the shell is non-interactive and doesn't do job control.

That cat however does nothing useful, it's the same UUOC as in:

cat | diff -u <(echo ok) -

Or

cat | diff -u <(echo ok) /dev/stdin

On systems that don't support /dev/fd/x / /dev/stdin¹, for commands which unlike diff, don't support - to specify stdin, <(cat) in bash or zsh (but not in ksh versions prior to ksh93u where that feature comes from) uses a temporary named pipe instead, so diff -u <(echo ok) <(cat) will still work on those systems.


¹ very few these days and there are probably far more systems without bash than without /dev/fd/x

Source Link
Stéphane Chazelas
  • 584.6k
  • 96
  • 1.1k
  • 1.7k
Loading