Home > Net >  Perfom piping if condition is true
Perfom piping if condition is true

Time:07-17

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}, and foo.txt.
  • If it's false it writes bar.txt, stdin, and foo.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
  • Related