52

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.

bmike
  • 235,889
gatorback
  • 3,031
  • 8
  • 40
  • 57
  • 1
    # is recognized as the comment character in scripts by zsh – lhf Oct 28 '20 at 13:36
  • 1
    The answer you link to seems to answer your question as well. What exactly are you missing? – nohillside Oct 28 '20 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 '20 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 '20 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 '20 at 19:54
  • 1
  • @user3439894 Thanks for the resource: I encourage all to click the link to vote to open the question so that your insight can be posted. – gatorback Oct 29 '20 at 12:02
  • 1
    The original design of the Z shell is based on the Korn shell and the C shell. The C shell allows the hashtag comment in shell scripts and not for interactive use. So, obviously, the C shell influences the Z shell. As the shell has matured, features from the Bourne Again shell and the ksh93 shell have been incorporated in the Z shell. – fd0 Oct 29 '20 at 12:11
  • Related, and with some background in the comments https://unix.stackexchange.com/questions/557486/allowing-comments-in-interactive-zsh-commands, https://stackoverflow.com/questions/11670935/comments-in-command-line-zsh – nohillside Oct 29 '20 at 12:38
  • Note that this effect can only occur in interactive zsh. In a script, which is usually executed by a non-interactive zsh, or in a script sourced by an interactive zsh, a # is always a comment. In an interactive zsh, it depends on your configuration whether or not you want the # to be understood as a comment. – user1934428 Jan 19 '23 at 08:21
  • They had to ship it tured off in order to have a better chance at taking home the "Dumbest Default Awards of 2019" gold medal. IMNSHO – conny Feb 08 '23 at 05:54
  • As you found out by yourself, this feature is configurable. Is there a particular reason why you want to have interactive comments? Actually, the # character is handy in interactive use for aliases or shell functions. – user1934428 Jan 24 '24 at 13:36
  • The question is posed to understand why a change was made as well as how to cope with the change. Because I had built a library scripts in the old style, I hope it is clear as to why. Understanding why the change was made is important to me from a pedagogical standpoint – gatorback Jan 24 '24 at 13:52

3 Answers3

11

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.

Allan
  • 101,432
  • 5
    Isn't the OP asking about why interactive_comments is on in bash but off in zsh by default ? – nohillside Oct 29 '20 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 '20 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 '20 at 15:11
  • Thanks @nohillside! I guess I'm not seeing it as "disabled" but rather "not set." For example, although the Thunderbolt ports on all MacBooks support MST, Apple disabled it on macOS (you can't daisy chain displays in macOS, but using Bootcamp and Windows, you can). – Allan Oct 29 '20 at 15:15
  • Do you know if there's a way to achieve the 'comment' functionality seemingly missing from zsh? I have a few dozen lines of code, which are commented with the usual #, but I want to allow users to copy/paste the code at will into the zsh, but it errors because of the comments. – stevec Apr 11 '22 at 04:28
  • 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 / – Cornelius Roemer Aug 04 '22 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. – vastlysuperiorman Oct 17 '22 at 14:57
  • @vastlysuperiorman And it isn't set by default by Apple Indeed, if you copy/paste some bash script and run on zsh, there's a chance it contains #, likely not ; though but a malicious documenter could employ this. Apple responded saying: works as designed ‍♂️ – Cornelius Roemer Oct 17 '22 at 16:27
  • For both bash and zsh, Apple has kept the default behavior with respect to # in interactive sessions. Most likely nobody at Apple considered this important enough to change, or if they did they eventually decided it was best to keep the default settings for the sake of people who are already familiar with bash/zsh or read documentation about it. As for why # is not a comment character by default in zsh, I don't know; the original author decided in the 1980s or early 1990s, and zsh is very conservative in its default settings. – Gilles 'SO- stop being evil' Jan 21 '23 at 21:42
  • "it's even more difficult to speculate why Zsh did/didn't do something" > Perhaps this is not so difficult. In zsh, the '#' character acts as an "extended globbing" function (match zero or more occurrences of the preceding character). Turning it into a comment would disable this functionality. There is no equivalent extended globbing in Bash, so it might as well be used for comments there. – Jonathan Hartley Oct 13 '23 at 13:21
9

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.

antonio
  • 199
  • 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 '23 at 05: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 '23 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 '23 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). – Gilles 'SO- stop being evil' Jan 21 '23 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. – Gilles 'SO- stop being evil' Jan 21 '23 at 21:37
  • Thanks @Gilles'SO-stopbeingevil'. It seems # should always introduce comments when it follows whitespace and always glob otherwise. If you put literal #s in your filenames, you deserve what you get. :-) – Denis Howe Jan 23 '23 at 00:38
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
    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 '23 at 18:18