【问题标题】:Bash printf %q invalid directiveBash printf %q 无效指令
【发布时间】:2014-11-22 00:31:43
【问题描述】:

我想在我的 .bashrc 文件中更改我的 PS1。 我发现了一个使用带有 %q 指令的 printf 来转义字符的脚本:

#!/bin/bash
STR=$(printf "%q" "PS1=\u@\h:\w\$ ")
sed -i '/PS1/c\'"$STR" ~/.bashrc

问题是我收到了这个错误:

script.sh: 2: printf: %q: invalid directive

有什么想法吗?也许是另一种逃避角色的方法?

【问题讨论】:

    标签: linux bash sed printf ps1


    【解决方案1】:

    printf 命令内置在 bash 中。它也是一个外部命令,通常安装在/usr/bin/printf 中。在大多数 Linux 系统上,/usr/bin/printf 是 GNU coreutils 实现。

    较早版本的 GNU coreutils printf 命令不支持 %q 格式说明符;它是在 2016 年 10 月 20 日发布的 8.25 版中引入的。 bash 的内置 printf 命令可以——并且只要 bash 有一个内置的 printf 命令。

    错误消息暗示您正在运行script.sh 使用的不是 bash。

    由于#!/bin/bash 行似乎是正确的,您可能正在执行以下操作之一:

    sh script.sh
    . script.sh
    source script.sh
    

    相反,直接执行它(确保它具有执行权限后,如果需要使用chmod +x):

    ./script.sh
    

    或者您可以手动编辑您的.bashrc 文件。如果正确执行,该脚本会将此行添加到您的.bashrc

    PS1=\\u@\\h:\\w\$\ 
    

    (该行末尾的空格很重要。)或者您可以更简单地这样做:

    PS1='\u@\h:\w\$ '
    

    脚本的一个问题是它会替换每个提到PS1的行。如果你只设置一次而不引用它,那很好,但如果你有类似的东西:

    if [ ... ] ; then
        PS1=this
    else
        PS1=that
    fi
    

    然后脚本会彻底搞砸。这有点太聪明了。

    【讨论】:

    • 这是手动操作比使用花哨的命令行更简单、更安全的情况之一。 :)
    • RE: The GNU coreutils printf command does not support the %q format specifier coreutils 文档现在提到了%q 指令:gnu.org/software/coreutils/printf
    • @JanusTroelsen:已更新。
    【解决方案2】:

    Keith Thompson 在他的回答中给出了很好的建议。但是 FWIW,您可以通过在命令名称前加上 builtin 来强制 bash 使用内置命令,例如

    builtin printf "%q" "PS1=\u@\h:\w\$ "
    

    反之,

    command printf "%s\n" some stuff

    强制 bash 使用外部命令(如果可以找到的话)。

    command 可用于在存在同名的函数 时调用磁盘上的命令。但是,command 确实调用磁盘上的命令来代替具有相同名称的 Bash 内置,它仅用于禁止调用 shell 函数。 (感谢 Rockallite 提醒我注意这个错误)。

    可以启用或禁用特定的 bash 内置函数(也许您的 .bashrc 正在对 printf 执行此操作)。有关详细信息,请参阅help enable。我想我应该提到你可以使用

    type printf
    

    找出当你给它一个赤裸裸的printf 时,bash 会运行什么样的实体(shell 函数、内置或外部命令)。您可以通过将type 传递给-a 选项来获取具有给定名称的所有命令的列表,例如

    type -a printf 
    

    您可以使用 grep 查看 .bashrc 文件中包含 PS1 的行:

    grep 'PS1' ~/.bashrc 
    

    grep -n0 --color=auto 'PS1=' ~/.bashrc
    

    它为您提供行号和精美的彩色输出。然后你可以使用行号来强制 sed 只修改你想要更改的行。

    例如,如果 grep 告诉您要更改的行是第 7 行,您可以这样做

    sed -i '7c\'"$STR" ~/.bashrc
    

    编辑它。甚至更好,

    sed -i~ '7c\'"$STR" ~/.bashrc
    

    它会备份文件的原始版本,以防万一出现错误。

    当使用sed -i 时,我通常先在不使用-i 的情况下进行测试运行,以便将输出发送到shell,让我在将修改写入文件之前查看它们的作用。

    【讨论】:

    • 我不认为在这种情况下使用 builtin printf 会有所帮助。 bash 默认使用内置的printf。如果在这种情况下没有使用它,那是因为被调用的 shell 不是 bash。
    • 嗯,是的。除非它在 ​​shell 启动期间被 enable -n printf 出于某种奇怪的原因禁用。但我同意你的理论更有可能,我只是提到它是一种可能性。
    • 嗯。不知何故,直到现在我才设法避免了解 enable 命令。有趣。
    • 我承认这有点晦涩。我自己最近才知道它:我在查找其他内置函数的详细信息时,在 bash 人中偶然发现了它。我相信它总有一天会派上用场的...... :)
    • enable -n enable 很诱人。
    猜你喜欢
    • 2012-08-23
    • 1970-01-01
    • 2012-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多