36

I can't pass strings starting with # as command-line arguments.

Here is a simple test:

#include <stdio.h>

int main(int argc, char *argv[])
{
    for (int i = 1; i < argc; i++)
        printf("%s ", argv[i]);

    putchar('\n');

    return 0;
}

If I input the arguments as follows:

2 4 # 5 6

The value of argc is 3 and not 6. It reads # and stops there. I don't know why, and I can't find the answer in my copies of The C Programming Language and C Primer Plus.

ggorlen
  • 44,755
  • 7
  • 76
  • 106
cd-00
  • 585
  • 5
  • 10

3 Answers3

47

# begins a comment in Unix shells, much like // in C.

This means that when the shell passes the arguments to the progam, it ignores everything following the #. Escaping it with a backslash or quotes will mean it is treated like the other parameters and the program should work as expected.

2 4 \# 5 6

or

2 4 '#' 5 6

or

2 4 "#" 5 6

Note that the # is a comment character only at the start of a word, so this should also work:

2 4#5 6
ilkkachu
  • 6,221
  • 16
  • 30
fanduin
  • 1,149
  • 10
  • 17
  • I also find that '$' ignore characters that follow it, but not others. Are there other special characters? – cd-00 Nov 13 '19 at 13:30
  • 2
    This seems to be a pretty good list https://unix.stackexchange.com/a/270979 – fanduin Nov 13 '19 at 13:35
  • 22
    @cd-00 You need to learn how the shell works. This has nothing to do with your C code. – chepner Nov 13 '19 at 13:44
  • 3
    Ah, so you can type comments in *interactive* shell sessions, so the shell can ignore it immedaitely after you've finished typing it. What a useful feature. – Joker_vD Nov 13 '19 at 22:14
  • 6
    @Joker_vD While you think of a shell as a command-line interface, it's actually a script interpreter. The fact that you can use it like an interactive CLI is a nice bonus. Why should the interpreted behave significantly differently when you are "running a script" versus typing commands in interactively? What about `echo echo Hello, World | bash`. Is that interactive? Or maybe `bash < – Christopher Schultz Nov 13 '19 at 22:53
  • 6
    @Joker_vD: I frequently type comments in interactive sessions to refer back to in my shell history. Sometimes this is to record a commit hash or other ID emitted to stdout; sometimes it’s to note that a command failed as a note to my future self; sometimes it’s to record timing data for ad hoc benchmarking. It *is* a useful feature. – wchargin Nov 14 '19 at 05:07
  • @Joker_vD: How much would it suck if the OP's command worked interactively, but *failed when copy/pasted into a shell script*? (Answer: not a huge amount because you can run the script with `bash -x` to trace commands). You can even disable interactive comments in bash with `shopt -u interactive_comments` – Peter Cordes Nov 14 '19 at 05:14
  • The handling of `#` also depends on the shell. I think zsh doesn't honor it as a comment character in interactive mode by default, and then there's the csh variants which might or might not do something different (I don't know). – ilkkachu Nov 14 '19 at 08:30
12

When passing the value through command line arguments you have to walk through these following instructions. The following characters have special meaning to the shell itself in some contexts and may need to be escaped in arguments:

` Backtick (U+0060 Grave Accent)
~ Tilde (U+007E)
! Exclamation mark (U+0021)
# Hash (U+0023 Number Sign)
$ Dollar sign (U+0024)
& Ampersand (U+0026)
* Asterisk (U+002A)
( Left Parenthesis (U+0028)
) Right parenthesis (U+0029)
 (⇥) Tab (U+0009)
{ Left brace (U+007B Left Curly Bracket)
[ Left square bracket (U+005B)
| Vertical bar (U+007C Vertical Line)
\ Backslash (U+005C Reverse Solidus)
; Semicolon (U+003B)
' Single quote / Apostrophe (U+0027)
" Double quote (U+0022)
↩ New line (U+000A)
< Less than (U+003C)
> Greater than (U+003E)
? Question mark (U+003F)
  Space (U+0020)1
VJAYSLN
  • 473
  • 4
  • 12
8

It's because you're using an sh-like shell. Quote the # or escape it using \ and it will work.

This is called a comment in sh. It causes the # (space-hash) and any arguments after it to be discarded. It's used similarly to comments in C, where it is used to document code.

Strings beginning with $ are called variables in sh. If you haven't set a variable, it will expand to an empty string.

For example, all of these would be valid ways to pass the # to your application:

2 4 '#' 5 6
2 4 "#" 5 6
2 4 \# 5 6

And these would be valid ways to pass a string starting with $:

2 4 '$var' 5 6
2 4 '$'var 5 6
2 4 \$var 5 6

Please note that variables inside "s are still expanded.

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76