12

I need to printf a simple script and redirect the output to a file, but when I do this:

printf "#!/bin/bash\ntouch /tmp/1234567890_$RUN" > /tmp/password-change-script_$RUN.sh

I get this error:

bash: !/bin/bash\ntouch: event not found

If I escape the exclamation mark:

printf "#\!/bin/bash\ntouch /tmp/1234567890_$RUN" > /tmp/password-change-script_$RUN.sh

Then the escape character is still present in the file.

cat /tmp/password-change-script_$RUN.sh
#\!/bin/bash
touch /tmp/1234567890_111

By the way, in this particular case, the #!/bin/bash MUST be in the file. For some reason the binary file that executes the script won't read the file otherwise.

David Mulder
  • 7,595
  • 11
  • 45
  • 61

2 Answers2

19

The ! character is expanded in double-quoted strings, but not in single-quoted strings.

printf '#!/bin/bash\ntouch /tmp/1234567890_'"$RUN"

It's also not expanded when it appears by itself or at the end of a word; this isn't as clean but:

printf "#%c/bin/bash\ntouch /tmp/1234567890_$RUN" !

You can also temporarily turn off history substitution by (temporarily) setting $histchars to the empty string; this turns off the special treatment of !:

histchars=
printf "#!/bin/bash\ntouch /tmp/1234567890_$RUN"
unset histchars

Or you can execute the printf command in a script rather than interactively (history substitution is on by default only for interactive shells).

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
14

Try doing this :

printf "\041"

This is the octal ASCII representation of ! character

See

man ascii

Another solution :

(
    set +o histexpand 
    printf "!"
)

(the parenthesis are used to change terminal setting in a subshell, so the change is temporary)

See

help set
set -o
Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223