4

Question

What are the semantics of : in regards to its use in pipes?

The Bash documentation states:

: [arguments]
No effect; the command does nothing beyond expanding arguments and performing any specified redirections. The return status is zero.

However, it's not obvious what behavior I ought to expect from : being used in a pipe. Does it simply pass through std{in,out,err}?

In regards to the arguments : can be a stand-in for any other command, it seems. But I need a clarification regarding the use in pipe; a clarification not merely based upon observation, but citing authoritative sources.

Background

I have a situation, where -- depending on the environment the script runs in --, I need to run the output through tr -d '\r' to remove carriage return characters from the output.

Alas, currently this means an if/else/fi block, along the lines of (inside a function):

if [[ "$OSTYPE" == "cygwin" ]]; then
    my_commands | tr -d '\r' || return $?
else
    my_commands || return $?
fi

Where the | tr -d '\r' is the only difference between the if and the else branch. The contents of either branch are of course quite a bit more complex than shown here.

Now, I get it that the tr -d '\r' is benign in cases where there is no carriage return. But it's an invocation and (on Windows) an overhead that could be avoided (the function is a "hot" code path). And so I thought of replacing tr by the builtin shell function :.

0xC0000022L
  • 16,593

3 Answers3

14

The pass-through replacement in this case is cat, which copies its input to its output. : does nothing so your input would be lost:

$ echo hello | :
$

In fact, since : doesn’t read its input, commands feeding the pipe will receive a SIGPIPE, so they might not finish their task, or even start it:

$ (seq 1 10000 | tee /dev/stderr; echo $? 1>&2) | :
141

Using cat means an external invocation, just like tr (but with slightly less work). Bash doesn’t have a pass-through built-in of this kind.

Stephen Kitt
  • 434,908
  • Thanks Stephen for this concise, yet comprehensive answer. Shatters my hopes, but helps a lot ;) – 0xC0000022L Jun 02 '23 at 08:48
  • I guess the doubt arose because in the context of filters what cat does is a no-op and what : does is "delete everything". – Kamil Maciorowski Jun 02 '23 at 08:50
  • 5
    @KamilMaciorowski I would call cat an "identity filter" rather than a "no-op". – Kusalananda Jun 02 '23 at 08:51
  • 1
    @KamilMaciorowski not quite, : doesn’t delete everything, it just doesn’t read anything — if the feeder command produces more output than the pipe buffer holds, it will get a SIGPIPE. – Stephen Kitt Jun 02 '23 at 09:35
  • 1
    Note also that, if you're one of those people who sets pipefail, then piping to : will count as a failed command, because the writer will probably die of SIGPIPE rather than exiting normally. This is why redirection to /dev/null is probably safer in most cases (and why pipefail should be used with care). – Kevin Jun 02 '23 at 21:26
  • A command that actually consumes all its input and emits no output would be sed d. But I'm having trouble coming up with any reason to prefer | sed d over > /dev/null. – John Bollinger Jun 04 '23 at 02:37
10

Regardless of the odd name, : is still a command and acts like one, so when it doesn't do anything, it means it also doesn't read anything from the pipe. It's not special syntax for the shell in the sense that | : | would reduce back to just |. The POSIX description for : does say it doesn't "use" stdin or stdout, but of course it doesn't explicitly mention pipelines there.

There are some solutions to this in Conditional pipeline, but mostly it's hard or awkward to avoid running a copy of cat in the middle.

(fine print: The POSIX text uses the term "utility", but it's still the same term used for e.g. ls. Also, : isn't exactly a regular command, but a "special built-in", which makes a difference in some minor cases, but not here.)

ilkkachu
  • 138,973
  • The only "use" that I have found for : is when I am building a script. Functions and if-then structures, etc. need something to execute. Suppose I've planned out the idea and what functions there will be. But I haven't worked out the code yet, and the : serves as a placeholder so the rest of the script runs without an error such as "syntax error near unexpected token `}'" . Then I can move on. I think it is a programming tool more than anything else. – Wastrel Jun 16 '23 at 23:36
3

The key phrase in the man page is that : (like its synonym true) does nothing. It doesn't read anything from its input, nor does it write anything to its output streams.

In a pipe, it's not very useful - it acts like a blockage in the plumbing.

Toby Speight
  • 8,678