The following Bash code works:
text="SPECIAL"
COND=true
if [ "$COND" = true ]; then printf "${text}"; else : ; fi | cat bar.txt - foo.txt > ./output.txt
It uses the no-op colon operator.
Though, the pipe operator is being executed regardless of the condition.
I was wondering whether the pipe operator itself may be avoided - given a specific condition is true.
For example, I was hoping that something like this would work (it doesn't work as I want it to, rather it does something else):
text="SPECIAL"
COND=true
if [ "$COND" = true ]; then printf "${text}" | ; fi cat bar.txt - foo.txt > ./output.txt
Reason is - I want that the program which receives the pipe (i.e. cat
in our example) wouldn't recognize any piping if some condition is true or false.
Meaning - the end result should be as follows:
If condition is true, then piping is enabled - as follows:
printf "${text}" | cat bar.txt - foo.txt > ./output.txt
If condition is false, then piping is disabled - as follows:
cat bar.txt - foo.txt > ./output.txt
CodePudding user response:
Essentially this can't be done, unless you messed around with eval
. A command is either part of pipeline, or it's not.
But in your first example, you don't need the else condition:
if [ "$COND" = true ]; then
printf "${text}"
fi |
cat bar.txt - foo.txt > output.txt
Or even:
{ [[ $COND == true ]] && printf "${text}"; } |
cat bar.txt - foo.txt > output.txt
Both insert $text
, only if the condition is met.
In this situation, there's also:
printf %s "${COND: $text}" |
cat a.txt - c.txt
If $COND
is empty, nothing is inserted. If $COND
is not empty, $text
is inserted.
You should also use an appropriate printf format string, like printf %s "$text"
.
If relevant, printf %s "${COND: $text$'\n'}"
will also add a trailing new line.
For multiple conditions, there's also:
cat a.txt \
<(printf %s "${cond1: $text1}") \
b.txt \
<(printf %s "${cond2: $text2}") \
c.txt
CodePudding user response:
You can use cat
instead of :
to forward stdin to the piped cat
. This effectively "nullifies" the pipeline by passing std
to the second cat
as if it were not part of a pipeline.
if [ "$COND" = true ]; then printf "${text}"; else cat; fi | cat bar.txt - foo.txt > ./output.txt
- If the condition is true it writes
bar.txt
,${text}
, andfoo.txt
. - If it's false it writes
bar.txt
, stdin, andfoo.txt
.
CodePudding user response:
Rather than trying to massage the pipe at the call site, consider manipulating the file descriptors. Something like:
#!/bin/sh
text='this is text'
trap 'rm -f "$tmpfile"' 0
tmpfile=$(mktemp)
rm "$tmpfile"
mkfifo "$tmpfile"
exec 3<&0 # Save stdin
if test "$1" = t; then
printf '%s\n' "$text" > "$tmpfile" &
exec 0< "$tmpfile"
else
:
fi
cat a - b
exec 0<&3 # Restore stdin