1

I had a tiny bash script that is supposed to move to my home directory, make a file, echo some junk onto it, and make it executable. This is what it looked like:

cd ; touch tor.sh; echo "#!/bin/bash\n/usr/local/bin/tor" >> tor.sh; chmod +x tor.sh

But this kept breaking at the echo, complaining about "event not found" ? For some reason I decided to try this and it worked:

cd ; touch tor.sh; echo -e "\x23\x21/bin/bash\n/usr/local/bin/tor" >> tor.sh; chmod +x tor.sh

Why did I have to replace those two characters (the shebang?) with hex and a -e? Is there a better way to do this?

Broseph
  • 1,655
  • 1
  • 18
  • 38

5 Answers5

4

This is not a bug and it has nothing to do with the shebang, just the exclamation point.

Enclosing  characters  in double quotes preserves the literal value of
all characters within the quotes, with the exception of $, `, \,  and,
when  history expansion is enabled, !.

So either escape it, use single quotes, or turn off history expansion.

e.g.

> echo "How dare you put an '!' in this string?"
bash: !: event not found
> set +o histexpand
> echo "How dare you put an '!' in this string?"
How dare you put an '!' in this string?
Reinstate Monica Please
  • 11,123
  • 3
  • 27
  • 48
  • You answered explained the cause of my problem in the most straightforward way, and that is the part I cared more about. But if I could, I'd also accept Red Cricket's answer. – Broseph Feb 01 '14 at 07:09
2

You should use single quotes to prevent string extrapolation:

echo '#!/bin/bash\n/usr/local/bin/tor'

Or you might escape shebang:

echo "#\!/bin/bash\n/usr/local/bin/tor"
Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
1

Use "\", like:

echo \#\!/whatever > test
Matías Insaurralde
  • 1,202
  • 10
  • 23
1

try ''s instead of "'s like this ...

$ echo '#!/bin/bash' > thing.sh
$ cat thing.sh
#!/bin/bash
Red Cricket
  • 9,762
  • 21
  • 81
  • 166
-1

Two reasons:

One, the difference in behavior between double and single-quoted strings.

"#!/bin/bash\n/usr/local/bin/tor" is "expanded" — that is, the commands within quotes here will be executed first.

Thus,
echo "$(echo foo)" > file puts 'foo' in file, while
echo '$(echo foo)' > file puts '$(echo foo)' in file.

"#!" is a comment, and this does not occur in other shells. If it begins a file (as a shebang), POSIX specifies that this is undefined behavior; but there's no reason why this should be happening here.

Geoff Nixon
  • 4,697
  • 2
  • 28
  • 34
  • Here is some more advanced discussion of the [treatment and effect of string expansion](http://stackoverflow.com/questions/448407/bash-script-to-receive-and-repass-quoted-parameters). – Geoff Nixon Feb 01 '14 at 05:13
  • I don't have enough reputation to comment on someone else's answer, so I guess I'll put this here: I stand by calling this a bug. Nowhere [here](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html) is that behavior specified; this cannot be reproduced in any other shell (dash ksh mksh pdksh yash). If it is a bashism, this should be disabled when invoked with `bash --posix`. – Geoff Nixon Feb 01 '14 at 06:03
  • So everything that can't be reproduced in other shells is a bug? – Reinstate Monica Please Feb 01 '14 at 06:14
  • I have no interest in engaging in a flame war with you, bro. Of course not; its a bug to claim to be implementing a standard, particularly in a strictly compliant mode, to introduce a different and incompatible behavior (plus, have no documentation for this deviation). – Geoff Nixon Feb 01 '14 at 06:23
  • Where do you think think the quote in my answer comes from? – Reinstate Monica Please Feb 01 '14 at 06:38
  • The bash documentation website. – Geoff Nixon Feb 01 '14 at 06:40
  • http://stackoverflow.com/questions/5725296/difference-between-sh-and-bash – Geoff Nixon Feb 01 '14 at 06:41
  • And also now http://stackoverflow.com/questions/21496049/what-is-the-intended-effective-ordering-of-set-o-options-in-bash-does-histe – tripleee Apr 07 '16 at 04:49