Is there a way to re-write the command structure A && B || C | D
so that either B or C is piped into D?
With the current command either only B or both C and D are run.
For example:
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.
Sign up to join this communityIs there a way to re-write the command structure A && B || C | D
so that either B or C is piped into D?
With the current command either only B or both C and D are run.
For example:
Yes, in bash you can use parentheses:
(A && B || C) | D
This way the output of A && B || C
will be piped into D
.
A
is inside the subshell, this also includes A
.)
– jpaugh
Apr 18 '17 at 15:48
You can write this as
if A; then B; else C; fi | D
You say you want to run either B
or C
, but A && B || C
doesn't achieve that. If A
succeeds, but B
runs and fails, it would execute C
.
Note 1: if you can somehow guarantee that B
always succeeds and want to stick with a short version, then I'd still opt for
{ A && B || C; } | D
over ( ... )
, as the latter unnecessarily forces a new subshell to be created, which may or may not get optimised away.
Note 2: both forms assume A
produces no output, which is true in your example but not necessarily so in general. That can be avoided by
A; if [ "$?" -eq 0 ]; then B; else C; fi | D
{ … }
does not force a subshell to be created due to the pipe? I observe the following behavior: pgrep bash
and pgrep bash | cat
and if true; then pgrep bash; fi
and { pgrep bash; }
have one line of output; ( pgrep bash; )
and ( pgrep bash; ) | cat
and { pgrep bash; } | cat
and if true; then pgrep bash; fi | cat
have two lines of output.
– wchargin
Apr 18 '17 at 2:10
... | ...
causes a subshell to be created, that's unavoidable. ( ... )
, at least in theory, causes an additional subshell to be created that { ...; }
avoids, but that's what I meant with "may or may not get optimised away": it's possible that in this particular case, the shell realises it doesn't matter, the effect would be the same.
– hvd
Apr 18 '17 at 4:51
The accepter answer is correct but it doesn't cover the potential use case to not have the output of A
as the input of D
. To achieve that you’ll need a stream redirection on A
depending on your needs.
If you want to discard the output of A
anyway:
{ A >/dev/null && B || C; } | D
If you want to see the output of A
on the terminal:
{ A >/dev/tty && B || C; } | D
If you need the output of A
as the input of a subsequent command E
you’ll need an additional command group and stream redirection:
{ { A >&3 && B || C; } | D; } 3>&1 | E
If all this looks too arcane to you (as it does to me) I recommend that you use the special shell variable for the exit status of A
and work with that:
A
if [ $? -eq 0 ]; then
B
else
C
fi |
D
If you want to be more concise but not too arcane I suggest this:
A; { [ $? -eq 0 ] && B || C; } | D
(See also the last part of hvd’s answer which I didn't notice when I wrote my original answer.)
A
out of the pipeline.
– hvd
Apr 17 '17 at 21:17