187

I'd like to be able to comment out a single flag in a one-line command. Bash only seems to have from # till end-of-line comments. I'm looking at tricks like:

ls -l $([ ] && -F is turned off) -a /etc

It's ugly, but better than nothing. Is there a better way?

The following seems to work, but I'm not sure whether it is portable:

ls -l `# -F is turned off` -a /etc
Ondra Žižka
  • 43,948
  • 41
  • 217
  • 277
Lajos Nagy
  • 9,075
  • 11
  • 44
  • 55
  • The `#comment` trick is also mentioned here: http://stackoverflow.com/questions/9522631/bash-how-to-put-line-comment-for-a-multi-line-command – Juha Palomäki Dec 20 '14 at 08:40
  • 3
    Following the [link](http://stackoverflow.com/a/12797512/1342186) mentioned by @Juha Palomäki, there is this wonderful trick `${IFS#comment}` introduced by @pjh in the comments. No sub-shell is invoked. – alexis Aug 12 '15 at 18:53
  • Does this answer your question? [How to put a line comment for a multi-line command](https://stackoverflow.com/questions/9522631/how-to-put-a-line-comment-for-a-multi-line-command) – Danny Varod Nov 17 '20 at 19:07

9 Answers9

164

My preferred is:

Commenting in a Bash script

This will have some overhead, but technically it does answer your question

echo abc `#put your comment here` \
     def `#another chance for a comment` \
     xyz etc

And for pipelines specifically, there is a cleaner solution with no overhead

echo abc |        # normal comment OK here
     tr a-z A-Z | # another normal comment OK here
     sort |       # the pipelines are automatically continued
     uniq         # final comment

How to put a line comment for a multi-line command

Rafareino
  • 2,515
  • 1
  • 19
  • 26
  • 4
    Note that you have to use backticks, `$(#comment)` does not work. – funroll Sep 27 '16 at 20:29
  • 2
    Some versions will consider the `)` as part of the commentary itself. Most of the challenges of bash are due to retro compatibility with older versions, and one common strategy is to use the oldest solution possible. – Rafareino Jan 16 '18 at 16:00
  • 3
    Note, this is not a real comment: `true && \`# comment\` && true` is a valid expression. A real comment would generate something like: `syntax error near unexpected token `&&'` – Sebastian Wagner Sep 13 '18 at 15:59
  • You are right @sebastianwagner, note also that it would fail in a OR short circuit or something like that, but I think it's as good as we can get without complicating things a lot. To me it's a sign that one needs a better language, but it can do great, maintaining the already built code with such 'coments' to document it. – Rafareino Sep 13 '18 at 17:19
  • Thanks that helped me out! – xiarnousx Oct 06 '18 at 15:46
  • 1
    I prefer `$: echo hello, $( : 'comment, comment.' ) foo`. You can even make multiline comments with that if you need to, though personally I have *NEVER* seen a case where this was needed enough to warrant embedding it in the middle of a command. – Paul Hodges Nov 07 '18 at 22:37
  • This is awesome! : D But it breaks my syntax highlighting in vim : / – user151841 May 09 '19 at 12:33
  • that form `# xxx` not works if the comment has a exclamation mark, see https://stackoverflow.com/questions/60166019/why-line-comment-tricks-for-bash-not-works-with-exclamation-mark – William Leung Feb 11 '20 at 09:50
  • Neat observation made at https://stackoverflow.com/questions/2524367/inline-comments-for-bash/23872003?noredirect=1#comment106416104_23872003 by @william-leung, but the '!' exclamation mark only triggers a history search it it is immediately followed by a non blank char, which would be weird in english text/comment. – Rafareino Feb 11 '20 at 19:34
  • @Rafareino I found this issue because I use this tricks and ref some github issue / pr (!number) in the comment – William Leung Jul 11 '20 at 09:43
63

I find it easiest (and most readable) to just copy the line and comment out the original version:

#Old version of ls:
#ls -l $([ ] && -F is turned off) -a /etc
ls -l -a /etc
Dan
  • 9,935
  • 15
  • 56
  • 66
  • 5
    but then it isn't inline? i suppose its fair to say that needing to do things this unsupported by bash is cause to find another way – ThorSummoner Nov 26 '18 at 23:53
30

$(: ...) is a little less ugly, but still not good.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • 3
    By this syntax you are firing a sub-shell, a comment is suposed to improve redability without changing the code behavior at all, but the time to lauch/end this sub shell will make your code to be slower (to say the least), why not use only the colon in the start of a new line? – Rafareino May 26 '14 at 14:13
  • 4
    With ${IFS#...} no sub-shell is invoked. – alexis Aug 12 '15 at 18:57
  • 7
    @Rafareino: yeah. But seriously, in 95% of applications this overhead won't matter at all. For many of the cases where it does matter, it would probably have been a good idea to use a faster language than Bash in the first place. – leftaroundabout Jan 19 '16 at 11:37
  • ... trouble is, the `$(: ...)` syntax doesn't actually seem to allow embedding comments: whereas ``echo "foo" `# comment` "bar"`` will terminate the comment at the second backtick, the supposed equivalent `echo "foo" $(: # comment) "bar"` doesn't parse anything behind the `#`. – leftaroundabout Jan 19 '16 at 11:43
  • Instead of backtick you can use single or double quotes inside the `$(: )` - for example: `echo "foo" $(: "# comment") "bar"` - not pretty, but meets the requirements – mcau Aug 19 '21 at 23:27
7

Here's my solution for inline comments in between multiple piped commands.

Example uncommented code:

    #!/bin/sh
    cat input.txt \
    | grep something \
    | sort -r

Solution for a pipe comment (using a helper function):

    #!/bin/sh
    pipe_comment() {
        cat - 
    }
    cat input.txt \
    | pipe_comment "filter down to lines that contain the word: something" \
    | grep something \
    | pipe_comment "reverse sort what is left" \
    | sort -r

Or if you prefer, here's the same solution without the helper function, but it's a little messier:

    #!/bin/sh
    cat input.txt \
    | cat - `: filter down to lines that contain the word: something` \
    | grep something \
    | cat - `: reverse sort what is left` \
    | sort -r
OlivierBlanvillain
  • 7,701
  • 4
  • 32
  • 51
KylePDavis
  • 1,730
  • 1
  • 13
  • 6
  • 10
    As an aside, if you move the pipe character to the end of the previous line, you can get rid of the yucky backslash-newlines. – tripleee Aug 03 '16 at 04:13
4

How about storing it in a variable?

#extraargs=-F
ls -l $extraargs -a /etc
Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
4

Most commands allow args to come in any order. Just move the commented flags to the end of the line:

ls -l -a /etc # -F is turned off

Then to turn it back on, just uncomment and remove the text:

ls -l -a /etc -F
leedm777
  • 23,444
  • 10
  • 58
  • 87
1

If you know a variable is empty, you could use it as a comment. Of course if it is not empty it will mess up your command.

ls -l ${1# -F is turned off} -a /etc

§ 10.2. Parameter Substitution

Zombo
  • 1
  • 62
  • 391
  • 407
0

For disabling a part of a command like a && b, I simply created an empty script x which is on path, so I can do things like:

mvn install && runProject

when I need to build, and

x mvn install && runProject

when not (using Ctrl + A and Ctrl + E to move to the beginning and end).

As noted in comments, another way to do that is Bash built-in : instead of x:

$  : Hello world, how are you? && echo "Fine."
Fine.
Ondra Žižka
  • 43,948
  • 41
  • 217
  • 277
0

It seems that $(...) doesn't survive from ps -ef.

My scenario is that I want to have a dummy param that can be used to identify the very process. Mostly I use this method, but the method is not workable everywhere. For example, python program.py would be like

mkdir -p MyProgramTag;python MyProgramTag/../program.py

The MyProgramTag would be the tag for identifying the process started.

socrates
  • 1,203
  • 11
  • 16