48

Many bash scripts invoke the #character to indicate a comment. Catalina migrated to zsh. The command:

# Comments should elicit no response

returns

zsh: command not found: #

I find useful command examples on the web: it is helpful to annotate commands with said #weblink so that it is captured in the history.

I did find this post: https://stackoverflow.com/a/11873793/4953146

  1. Is there a reason for the # not to be recognized as the comment character in zsh?
  2. How can the terminal be configured to recognize the character as a comment?

Question 1 sets the context for deciding on a method to address question 2. It would nice to be able to configure the character once and all future instances of zsh would follow. If there is / was a good reason why the feature was disabled, I would like to understand any reasons.

Understanding the 'why' is important to determine the 'how'. There seems to be many ways to restore # commenting in zsh. One durable solution is to add to the configuration file: sudo vi /etc/zshrc:

setopt interactivecomments

Other methods (not durable) include invoking ksh or sh.

Many thanks to user3439894 & Allan for supporting / advancing the question.

11
  • 1
    # is recognized as the comment character in scripts by zsh
    – lhf
    Oct 28, 2020 at 13:36
  • 1
    The answer you link to seems to answer your question as well. What exactly are you missing?
    – nohillside
    Oct 28, 2020 at 14:00
  • 1
    I seek to understand not only the mechanics of enabling # as the comment character, but to understand the context as to why it is disabled and any possible unintended consequences of enabling #. This context would serve to better choose a method of enablement.
    – gatorback
    Oct 28, 2020 at 14:07
  • 1
    To enable permanently just put the command into .zshlogin or .zshrc. Discussions about design decisions made by the zsh developers are most probably off-topic here.
    – nohillside
    Oct 28, 2020 at 14:09
  • 5
    This question should be reopened. The # within a script is interpreted as comment (correctly) but issued by itself on the command line it throws that error. I'm endeavoring to find out why myself! Good question +1
    – Allan
    Oct 28, 2020 at 19:54

3 Answers 3

10

This is due to how Bash/Zsh is configured to handle comment characters in interactive and non-interactive shells.

Normally, comment characters are not recognized in interactive shells by default, so this behavior is normal.

From the Bash Reference Manual, Chapter 3.1.3 - Comments:

In a non-interactive shell, or an interactive shell in which the interactive_comments option to the shopt builtin is enabled , a word beginning with ‘#’ causes that word and all remaining characters on that line to be ignored. An interactive shell without the interactive_comments option enabled does not allow comments. The interactive_comments option is on by default in interactive shells.

The difference between interactive and non-interactive shells is that in the former, input and output is via the user's terminal whereas in the latter commands are asynchronous (no interaction). Though you are in an interactive shell, when you start a script, a non-interactive subshell is created.

Though I've referenced Bash in this answer, Zsh is the same. Chapter 6.7 - Comments reads almost the same:

In non-interactive shells, or in interactive shells with the INTERACTIVE_COMMENTS option set, a word beginning with the third character of the histchars parameter (‘#’ by default) causes that word and all the following characters up to a newline to be ignored.


If there is / was a good reason why the feature was disabled, I would like to understand any reasons.

I hesitate to use the word "disabled" as it's merely an environment variable that sets up the execution environment; it's simply "not set" by default. There's no documentation as to the reasoning why Apple (ultimately) chose to set it.

I can confirm that in other operating systems I've tested (FreeBSD and Debian), I installed Zsh (v5.8) and in both, the behavior described is the same as it is here - it's not set. This points to a decision by the Zsh folks that this was their preferred behavior of the execution environment. As we can't speculate as to why Apple did something, it's even more difficult to speculate why Zsh did/didn't do something and why Apple didn't modify it. Though it's probably a safe bet that Apple just went with the defaults.

10
  • 5
    Isn't the OP asking about why interactive_comments is on in bash but off in zsh by default ?
    – nohillside
    Oct 29, 2020 at 15:04
  • I didn't get that from the reading @nohillside just that he used comments and bash and when he came to ZSH he couldn't understand why he got "command not found". Thing is, it's a default setting.
    – Allan
    Oct 29, 2020 at 15:07
  • 1
    From the Q: " If there is / was a good reason why the feature was disabled, I would like to understand any reasons.". So basically the OP seems to know the answer already and I still think there is no real question at all here, but trying to keep an open mind :-)
    – nohillside
    Oct 29, 2020 at 15:11
  • 3
    This seems quite dangerous. This looks like a harmless comment, while the things up to ; are not executed because # is not recognised, the following command will erase your system... # Do not run this on Mac zsh; rm -rf / Aug 4, 2022 at 16:03
  • 2
    @CorneliusRoemer that example depends on someone adding a semicolon to the comment, but I agree with the sentiment completely. I often start writing out a long command, realize I need an extra detail, comment the whole line and execute. Then it's in my history to come back to when I've got the rest of the info. Not having interactive_comments set would indeed be dangerous. Oct 17, 2022 at 14:57
5

I disagree with this answer. It is not a matter of going with defaults. ("Apple just went with the defaults."), but a matter of features.

In zsh the # symbol works like a regexp quantifier, providing extended globbing. So

ls fo#                                                                                                         

matches the files:

f fo foo

and so on, that is zero or more o. While the double # matches one or more characters, that is:

ls fo##

matches

fo foo

While for interactive use this type of globbing is convenient, in a script it is better to use proper regexps. In particular, ls is discouraged for scripts, because it cannot be parsed reliably, in favour of find, which sports a -regex option to execute a command for each matching path.

Because in (long) scripts comments are necessary, but we can do without hash-globbing, they are activated. Instead, in interactive use, it is assumed that the benefits of globbing outweigh the lack of comments.

In Bash, there is no such a globbing feature, so it is conveninent to always have the commenting #. However, you can restore the interactive comments in zsh too with:

setopt interactive_comments

In this case, given:

ls fo#
ls fo # this is a comment 

the first # works as a glob, the second after a space, is a comment.
You can also disable extended globbing altogether with:

unsetopt extended_glob

That being the case, and while zsh is in many ways superior to Bash, replacing Bash with zsh was a poor design choice. In fact, zsh differs from Bash in several subtle ways, and your collection of one-liners might not work as expected. Microsoft adopted a better approach when introducing their new shell: it was not the new default, but just a new (better) alternative.

6
  • Regarding your last paragraph: it‘s the same on macOS: zsh is the default shell for new accounts, so existing users keep bash as their login shell until they manually switch (or install bashv5 via Homebrew).
    – nohillside
    Jan 18 at 5:55
  • 1
    Thanks @antonio for mentioning extended globbing, which I'd not heard of. That explains why # wasn't configured to work as expected by default in zsh. It's a Bad Decision because it prevents you from copying commands with comments and pasting them into a terminal (with due caution and understanding of course). For example, I wanted to comment some commands in our wiki for other people to use interactively, but they don't work in zsh.
    – Denis Howe
    Jan 20 at 17:53
  • @DenisHowe: It is particular annoying if you have a collection of one-liners with right inline comments, as copying only the left side is time-consuming. However, unsetopt extended_glob is your friend, if you can educate your readers.
    – antonio
    Jan 20 at 19:14
  • 1
    @DenisHowe I don't know why zsh doesn't treat # as a comment start by default, but it has nothing to do with globbing. # only starts a comment when it's after whitespace, and in this position it would not be a globbing character. And that would apply equally to scripts anyway. Globbing is just as useful in scripts as in the command line (and extended_glob is active in all the completion code). Jan 21 at 21:32
  • Beyond my previous comment, there are more errors in this answer. Bash has a similar globbing feature (activated by shopt -s extglob), but with a different syntax (also available in zsh with setopt ksh_glob — it's originally from ksh). There is no relation between using # or other extended_glob syntax and using ls or find, and no reason not to activate extended_glob other than strict compatibility with early-1990s zsh. Zsh hasn't replaced bash on macOS: it's an alternative, which has recently been made the default interactive shell for new accounts and does not affect scripts. Jan 21 at 21:37
2

Not an answer but a work-around:

The bash/zsh do-nothing built-in command, :, can be used for simple end-of-line comments. Beware though, because it is a command, not a comment, (a) you need to precede it with a ; and (b) it expands its arguments. So, for example, : ... $(rm foo) or : ... ; rm foo will execute the command rm foo, which may not be what the reader is expecting.

1
  • 1
    Also, things like echo foobar; : this is a comment; rm -rf ~ might be rather dangerous, so I wouldn't recommend this approach at all.
    – nohillside
    Jan 20 at 18:18

You must log in to answer this question.

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