0

I have a command piping an encrypted gpg stream into curl:

echo "Some Text" | gpg -o - | curl --silent -T - \
-X PUT \
--output /dev/null \
${myurl} \

When running this, I see something like

 % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0Enter passphrase

Passphrase:

where the "Enter passphrase" part is attached to the send of the curl output. I am unable to put in newlines due to the piped nature of things. Is there a way to make the curl output run later?

1 Answers1

2

How to prevent curl output from printing a preceding pipe's output?

curl does not print the "preceding pipe's output". What happens is curl and gpg print some messages to your terminal. The messages interfere with each other.

Remember that piped commands run concurrently.


If you expect the output from successful gpg never to be empty then use ifne:

… | gpg … | ifne curl …

(In Debian ifne is in the moreutils package.)

The main purpose of ifne is to prevent a command (here: curl) from running if the stdin is empty. To know if the stdin is really empty, the tool needs to wait for any data or EOF. This delays the actual command. A delay is what you need.

I expect gpg to start printing only after it gets the right passphrase. I did not test ifne thoroughly with preceding gpg asking for passphrase, but I did test with sudo … asking for password. If gpg works as I expect then ifne can help you. It will run curl after you provide the passphrase.

Note ifne will prevent curl from running if gpg prints nothing to its stdout (e.g. because the passphrase was wrong). This behavior is often desired. However if the output from successful gpg can be empty and still should be piped to curl, then ifne alone is not the right thing.

If you want to run curl regardless if gpg prints anything then keep reading.


The code below is a reduced version of my report script from this answer. Save it as delay.

It uses ifne in a more complicated way. The code must be an executable script (I mean don't try to make it a shell function) because it calls itself via ifne "$0" (and ifne cannot run a function).

#!/bin/bash

if [ "$1" = "-X" ]; then marker=1 fd="$2" shift 2 else unset marker exec {fd}>&1 fi

if [ "$marker" ]; then ( >&"$fd" "$@" ) else ifne -n "$0" -X "$fd" "$@" | ifne "$0" -X "$fd" "$@" fi

The purpose of delay is to delay execution of a command until there is data or EOF in the stdin. It was designed to be used after |.

You should use it like this:

… | gpg … | delay curl …

curl will run only after gpg starts printing to its stdout or closes for whatever reason.

Some technical details are explained in the already linked answer.


The difference between ifne foo, ifne -n foo and delay foo:

  • ifne foo waits for data or EOF and then runs foo iff there is data,
  • ifne -n foo waits for data or EOF and then runs foo iff there is no data,
  • delay foo waits for data or EOF and then runs foo unconditionally.