Use single quotes:
echo -e '#!/usr/bin/python\nimport string as s,random;print "".join(random.sample(s.letters+s.digits+s.punctuation,9))'>pg;chmod +x pg;./pg
The rules for !
were sort of grafted onto the other quoting rules afterwards (from csh). They were very useful back when shells didn't have command line editing, but some people still use them now.
P.S. Since you're coding for bash:
echo $'#!/usr/bin/python\nimport string as s,random;print"".join(random.sample(s.letters+s.digits+s.punctuation,9))'>pg;chmod +x pg;./pg
This works on most unices:
echo python -c \''import string as s,random;print"".join(random.sample(s.letters+s.digits+s.punctuation,9))'\'>pg;chmod +x pg;./pg
(Not that I understand why you want to create a script or why the script name has to be two letters.)
The !
character invokes bash's history substitution (enabled by default in interactive shells). When followed by a string (as in your failing example) it tries to expand to the last history event that began with that string. Just like $var
gets expanded to the value of that string, !echo
would expand to the last echo command in your history.
Space is a breaking character in such expansions. First note how this would work with variables:
# var="like"
# echo "$var"
like
# echo "$"
$
# echo "Do you $var frogs?"
Do you like frogs? <- as expected, variable name broken at space
# echo "Do you $varfrogs?"
Do you? <- $varfrogs not defined, replaced with blank
# echo "Do you $ var frogs?"
Do you $ var frogs? <- $ not a valid variable name, ignored
The same thing will happen for history expansion. The bang character (!
) starts off a history replacement sequence, but only if followed by a string. Following it with a space make it literal bang instead of part of a replace sequence.
You can avoid this kind of replacement for both variable and history expantion by using single quotes. Your first examples used single quotes and so ran fine. Your last examples are in double quotes and thus bash scanned them for expantion sequences before it did anything else. The only reason the first one didn't trip is that that the space is a break character as shown above.
Best Answer
There's no need to escape it if you just want an exclamation mark in the prompt.
See what happens.