如何在Bash中使用printf打印感叹号?

12
我需要使用printf打印一个简单的脚本,并将输出重定向到文件,但当我这样做时:

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

我遇到了这个错误:

bash: !/bin/bash\ntouch: 找不到事件

如果我转义感叹号:

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

然后转义字符仍然存在于文件中。

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

顺便提一下,在这种情况下,文件中必须包含 #!/bin/bash。由于某种原因,执行脚本的二进制文件否则无法读取该文件。
2个回答

19
在双引号字符串中,!字符会被扩展,但在单引号字符串中不会。
printf '#!/bin/bash\ntouch /tmp/1234567890_'"$RUN"

它出现在单独的词或单词末尾时也不会被扩展;虽然不够清晰,但这是可以接受的:
printf "#%c/bin/bash\ntouch /tmp/1234567890_$RUN" !

您也可以通过(临时)将$histchars设置为空字符串来暂时关闭历史替换;这将关闭对!的特殊处理:

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

或者你可以在脚本中执行printf命令,而不是交互式地执行(历史替换默认仅对交互式shell启用)。


@David:我已经更新了我的答案,加入了另外几个选择。 - Keith Thompson

14
尝试做这个:
printf "\041"

这是字符 ! 的八进制 ASCII 表示。
请参见。
man ascii

另一个解决方案:
(
    set +o histexpand 
    printf "!"
)

(这里的括号用于在子shell中更改终端设置,因此更改是暂时的)
请参见
help set
set -o

实际上,这只在单引号中起作用,printf '!' 也是如此。 - David Mulder
请看我在编辑后的帖子中的第二个解决方案。 - Gilles Quénot
这适用于单引号和双引号,就像我在帖子中所示。 - Gilles Quénot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接