17

When creating shell scripts using pipelines, and using the backslash to continue lines, I want to insert comments on separate lines, in a robust, readable and portable fashion.

For example, given this uncommented multi-line command (stolen from @DigitalRoss for its clarity):

echo abc |
     tr a-z A-Z |
     sort |
     uniq

... the below is aesthetically closest to what I want to accomplish, but for obvious reasons, does not work ... and yes, I'm well aware that this isn't something normally worth commenting:

# Perform critical system task.
# NOTE - An example of what does *not* work.
echo abc |
    # Convert lowercase to uppercase.
     tr a-z A-Z |

     # Sort the results.
     sort |

     # Only show unique lines.
     uniq

Existing related answers appear unsatisfactory for me, as follows:

First, glenn jackman's answer (adding arguments to an array, and then executing the array) works for single commands, but does not work for pipelining (and even if it did, it adds complexity that I would like to avoid).

Second, @Gilles' answer here (which uses :) also doesn't appear to work with pipelining, because it alters the flow of the pipeline:

$ echo "abc" | :
$

(NOTE: If there is an equivalent to : that passes output unmodified, that would be aesthetically acceptable, but I haven't been able to find one. I could write a custom one, but it would reduce portability.)

Finally, the last part of DigitalRoss' answer on StackOverflow works well for adding comments on the same line, but I strongly prefer comments on separate lines. Otherwise, when lines have widely varying lengths, readability is reduced:

echo abc |         # normal comment OK here`
     /usr/local/bin/really/long/path/ridiculously-long-filename.sh |  # another normal comment OK here
     sort |        # the pipelines are automatically continued
     uniq          # final comment

I'm looking for answers that preserve readability and minimize complexity, or else some background on why what I'm looking for is infeasible.

3
  • 1
    Note about your comments: I was taught to write comments explaining a section or unit of work. If an experienced coder writes intelligent comments describing what they're doing, then presumably anyone coming along maintaining the script can always use man pages if they don't understand the details of use. One should never write a comment like i++; // increment i by one. I suggest you read "The Elements of Programming Style"
    – bsd
    Dec 13, 2011 at 17:57
  • I think I'm going to delete the last edit. It's unusual for a question to contain the question, refutations of answers, and the answer itself, but the part that explains why other answers don't work is kind of necessary here. rozcietrzewiacz's answer and your comment together explain the problem though (personally I would've posted a separate answer and accepted it, since the problem was fairly different from what he described, but this works) Dec 14, 2011 at 14:46
  • Understood - thanks for the feedback; lesson learned! Dec 14, 2011 at 15:03

2 Answers 2

17

How about this?

echo abc | \
# Convert lowercase to uppercase.
tr a-z A-Z | \

# Sort the results.
sort | \

# Only show unique lines.
uniq

(The backslash needs to be used as the last character in those lines.) I'm not sure about the portability of that approach, but it sure works with current bash.

3
  • 1
    Aha! (facepalm) I transformed the idiom I was actually using when posting the question without realizing it! I was putting the pipe at the beginning of each line, which I am happy to stop doing now that I know that this method works well on all of the systems I can reach, in both bash and sh. Thanks! Dec 14, 2011 at 0:28
  • 1
    Wouldn't those comments ruin the line continuations? Mar 3, 2017 at 8:41
  • 1
    As long as there is an empty line before each comment, it works fine. Apr 12, 2017 at 3:22
2

This is kind of silly and inefficient but it does work, and it works with the |-first style.

# Add a comment to a pipeline, old-school BASIC-style
function REM {
  cat
}

cmd1 \
| REM "comment on cmd2" \
| cmd2 \
| REM "comment on cmd3" \
| cmd3

That said, if I saw it in production code, I'd probably be unhappy and go yell at whoever wrote it, so use, uh, with caution.

More seriously, how about a {} block?

cmd1 \
| {
  # comment on cmd2
  cmd2
} \
| {
  # comment on cmd3
  cmd3
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .