命令在本地有效,但使用 ssh 调用时返回“未找到事件”

命令在本地有效,但使用 ssh 调用时返回“未找到事件”

我想检查只读文件系统。我写了这个awk命令,它运行正常:

awk '{ if ( $4 ~ /ro,/ && $2 !~ /sys/ ) {print $2} }' /proc/mounts

我想将此命令与 一起使用ssh。这不起作用:

$ ssh ip "awk '{ if ( $4 ~ /ro,/ && $2 !~ /sys/ ) {print $2} }' /proc/mounts"  
bash: !~: event not found

我该怎么做?问题是由于波浪符号引起的吗?

答案1

波浪号不是罪魁祸首,感叹号才是。

双引号!~触发本地 shell 中的历史替换。请注意,内部单引号在本地无关紧要(比较,类似的情况;但是内部引号在远程 shell 中很重要)。

您需要让其!~在本地 shell 中显示为单引号。问题是您希望在远程 shell 中使用单引号。因此,您无法轻易嵌套引号。

您可以使用 禁用本地 shell 中的历史记录替换,set +H并坚持在本地使用双引号。但请注意,您不希望$4或被$2任何 shell(包括本地 shell)扩展。因此,无论如何您都需要在本地使用单引号;或者使用 进行转义$\例如\$2

转义\只能通过不带引号的 来帮助进行不必要的历史替换\!。双引号\!将阻止历史替换,但这\不会消失,它会在以后破坏一切。

可能的方法:

  1. 不加引号并转义!

    # history substitution may be enabled
    ssh ip "awk '{ if ( \$4 ~ /ro,/ && \$2 "\!"~ /sys/ ) {print \$2} }' /proc/mounts"
            ^^^^-double-quoted locally-^^^^    ^^^^^^^-double-quoted locally-^^^^^^^
                           unquoted locally ^^
    
  2. 禁用历史替换:

    set +H
    ssh ip "awk '{ if ( \$4 ~ /ro,/ && \$2 !~ /sys/ ) {print \$2} }' /proc/mounts"
    # re-enable history expansion (invoke `set -H') here if needed
    
  3. 将所有内容(除了在远程 shell 中至关重要的内部单引号)都用单引号引起来:

    # history substitution may be enabled
    ssh ip 'awk '"'"'{ if ( $4 ~ /ro,/ && $2 !~ /sys/ ) {print $2} }'"'"' /proc/mounts'
            ^^^^     ^^^^^^^^^^^^-single-quoted locally-^^^^^^^^^^^^     ^^^^^^^^^^^^^
                  ^               double-quoted locally               ^
    
  4. 在本地对所有内容使用单引号,在远程 shell 中使用双引号。这会将您的问题推送到远程 shell,因此您无论如何都需要处理它们:

    ssh ip 'awk "{ if ( \$4 ~ /ro,/ && \$2 !~ /sys/ ) {print \$2} }" /proc/mounts'
    

    惊喜!我们逃脱了$,但没有!~;并且没有set +H,但命令有效。

    这是因为ssh会产生一个非交互式远程端的 shell。非交互式 Bash 默认禁用历史记录扩展(请注意,远程 shell 可能不是 Bash,也可能根本不支持历史记录)。这使得主要问题消失。如果您以非交互式方式运行原始命令,例如ssh在本地脚本中(尽管您仍然需要转义$字符),相同的机制将对您有所帮助。

答案2

对我来说,bash 似乎正在将 ! 预先解释为其历史功能的一部分。

您是否尝试过用 \ 转义 ! ?请参阅 如何在 Makefile 中通过 SSH 命令转义字符

相关内容