如何方便地在 Bash 中单引号或转义整个命令行?

如何方便地在 Bash 中单引号或转义整个命令行?

介绍

考虑一个这样的工具watch可以接受另一个命令(例如ls -l),如下所示:

watch ls -l
# or equivalently
watch 'ls -l'

如果命令更复杂,则只需引用/转义,例如,,,$variable或由当前 shell 解释或转到。这两个命令不同:*|;&&watch

watch echo "$$"
watch 'echo "$$"'

这些也是:

watch date ; echo done
watch date \; echo done

ssh类似,它可以接受一个或多个参数并构建要在服务器上运行的命令。这取决于本地 shell 是否解释$variable,|等,或远程 shell 是否解释 , 等。

还有一些命令,例如sh -c,需要包含代码的单个参数,但引用/转义的需要是类似的。事实上,watch(或)为或类似命令ssh构建了这个单个参数。sh -c


问题

我已经有了精确的我想要提供给watchssh或类似工具的命令。该命令是从历史记录中获取的,或粘贴到命令行中,或键入,就好像它将直接执行一样;它在我的命令行中逐字逐句。没有什么在命令到达watch或类似工具之前,应该对其进行扩展或解释。如果是,则watch意味着所有扩展和解释都应稍后定期进行。如果是,则ssh意味着它应该在服务器上进行。

现在我需要做两件事:

  • watch在开头添加(或其他)。这不是问题。我可以最后做这件事。
  • 引用和/或转义原始命令。通常,命令可以包含单引号,因此盲目地使用单引号并不是解决方案。我想我知道正确的通用解决方案:

    • 将所有替换''"'"''\''
    • 用单引号括住整个结果字符串;

    但手动执行此操作非常繁琐且容易出错。


问题

我可以让 Bash 根据需要正确地为整个命令行添加一级单引用/转义吗?

(注:这个问题是我在回答时提出的这个

答案1

解决方案

是的。我的想法是调用一个 shell 函数(通过按键)来READLINE_LINE使用该${variable@Q}功能进行操作。

文档的相关部分:

${parameter@operator}

扩展是 值的变换parameter或有关其自身的信息parameter,具体取决于 的值operator。每个operator都是一个字母:

Q
parameter扩展名是一个字符串,它是用可以重复用作输入的格式引用 的值。

来源

READLINE_LINE
Readline 行缓冲区的内容,用于bind -x[…]。

来源

以下操作在 Bash 4.4.20 中有效:

_quote_all() { READLINE_LINE="${READLINE_LINE@Q}"; }
bind -x '"\C-x\C-o":_quote_all'

为了测试解决方案,请在命令行中准备一个命令(不执行),例如

d="$(LC_ALL=C date)"; printf 'It'\''s now %s\n' "$d"

(引用和整个命令可以简化。这是故意的。你执行它以确保它是一个有效的命令,但在继续之前将其放回命令行。)

Ctrl+ x, Ctrl+ o,它将被正确地引用/转义以达到我们的目的。它看起来会像这样:

'd="$(LC_ALL=C date)"; printf '\''It'\''\'\'''\''s now %s\n'\'' "$d"'

现在你需要做的就是在前面添加watch(或ssh …,或其他)并执行。如果是,watch请注意标题如下

Every 2.0s: d="$(LC_ALL=C date)"; printf 'It'\''s now %s\n' "$d"

它包含原始命令。命令已正确到达watch,没有部分被过早解释。


改进

为了方便起见,考虑这个变体:

_quote_all() { READLINE_LINE=" ${READLINE_LINE@Q}"; READLINE_POINT=0; }

它将准备行并将光标放在开头,以便您可以watch立即输入。或者甚至可能是这个变体(它故意使用不同的名称,我们正在为它创建单独的绑定):

_prepend_watch() { READLINE_LINE="watch  ${READLINE_LINE@Q}"; READLINE_POINT=6; }
bind -x '"\C-x\C-w":_prepend_watch'

现在Ctrl+ xCtrl+w处理引用,watch自动插入并将光标放在正确的位置以便您键入选项。

使用另一个函数READLINE_POINT可以处理以下情况:键入watch(或ssh …)后跟命令,其中引用/转义就像命令将直接执行一样。将光标放在命令开始的位置,按下按键,让函数修改从光标到行尾的所有内容。我在这里不提供这样的函数;如果你需要它,请自己编写。


Yo Dawg,我听说你喜欢引用

你可以堆叠解决方案。我的意思是你可以从这个开始

df -h | grep -v tmpfs

对此

watch 'df -h | grep -v tmpfs'

对此

ssh hostB -t 'watch '\''df -h | grep -v tmpfs'\'''

对此

ssh -t hostA 'ssh -t hostB '\''watch '\''\'\'''\''df -h | grep -v tmpfs'\''\'\'''\'''\'''

(是的,我知道ssh -J

只需在每个步骤中点击Ctrl+ xCtrl+o并在前面添加一个或几个单词即可。

相关内容