【问题标题】:KSH: How to escape backslash and double quotes togetherKSH:如何一起转义反斜杠和双引号
【发布时间】:2020-11-03 21:29:48
【问题描述】:

我不能强制 KSH 将 \" 作为参数传递给命令。 我想被执行的字面意思是:

command \"foo bar\"

以下示例在 ksh 中执行,并预先执行 set -x 以显示每个命令的回显,以将其执行的确切格式(在它被 ksh 解析之后)

[oracle@localhost sf_vm]$ ksh
$ set -x

我尝试并得到的是:

$ command \"foo bar\"
+ command '"foo' 'bar"'

不是我需要的:缺少 \ 和额外的 ' 和 "

$ command \\\"foo bar\\\"
+ command '\"foo' 'bar\"'

又不走运了:在 foo 和 bar 之外和之间增加了 '

$ command "\\\"foo bar\\\""
+ command '\"foo bar\"'

几乎正确,但在外面仍然不需要 '

$ command '\"foo bar\"'
+ command '\"foo bar\"'

再次几乎正确,但仍然'在外面

实际用例是我将 USERID 参数传递给 oracle expdb 命令,格式为 expdp USERID=/ AS SYSDBA 需要用转义双引号括起来,如下所示:

expdp USERID=\"/ AS SYSDBA\"

我知道我可以通过为 expdp 使用 prm 文件来解决此问题,但在我的情况下它非常不方便(自动导出)

如果有什么不同,我使用的是 ksh93 版本:

[oracle@localhost sf_vm]$ ll /etc/alternatives/ksh
lrwxrwxrwx. 1 root root 10 Oct 15  2018 /etc/alternatives/ksh -> /bin/ksh93

【问题讨论】:

  • set -x 记录的内容是传递给您的命令的人类可读表示实际数据是一个C字符串数组;它必须被转义才能成为人类可读的。
  • 那么,当您说要执行command \"foo bar\" 时,您希望执行的C 字符串数组究竟 是什么?因为我希望运行的是数组——以 JSON 格式表示——["command", "\"foo", "bar\""]。是你要使用的数组吗?
  • (要清楚:command '"foo' 'bar"' 是与 JSON 字符串 ["command", "\"foo", "bar\""] 对齐的 argv 的有效 shell 语法,也就是说,shell 告诉你它做了什么您要求,而您只是误解了它用于此的语法)。
  • 相比之下,如果你想要的是command "foo bar",那么不要使用反斜杠。当它们被省略时,双引号被视为语法而不是文字数据。
  • 谢谢查尔斯,你指出的让我找到了问题的真正根本原因,正如我在答案中描述的那样。

标签: shell unix ksh


【解决方案1】:

让我们从您的用例开始。

您断言的以下命令有效

expdp USERID=\"/ AS SYSDBA\"

评估为一个相当不直观的参数列表,如下所示(请注意,此特定代码仅适用于任何地方都不包含文字换行符的参数列表):

$ printf '%s\n' expdp USERID=\"/ AS SYSDBA\" | jq -Rnc '[inputs]'
["expdp","USERID=\"/","AS","SYSDBA\""]

...也就是说,您在第 0 个/第一个参数之外传递了三个参数 expdpUSERID="/ 是第一个参数,AS 是第二个参数,SYSDBA" 是第三个参数争论。当其set -x 实现将此参数列表打印为expdp 'USERID="/' AS 'SYSDBA"' 时,shell 是正确的,因为该参数列表 eval 与上述相同。

坦率地说,我非常怀疑这对于任何工具来说实际上是正确的/预期的用法。如果您的反斜杠没有被转义,并且您的预期用途是 expdp USERID="/ AS SYSDBA",这将更有意义,这将评估为(在 JSON 语法中)["expdp", "USERID=/ AS SYSDBA"]

【讨论】:

  • expdp的语法如下expdp PARAM1=VALUE1 PARAM2=VALUE2等等。当 VALUE 没有空格时,它工作得很好。当 VALUE 有空格时,它应该用双引号括起来,即 PARAM="VALUE WITH SPACE" 但这似乎在 ksh 中不起作用
  • 所有 POSIX 风格的 shell(不仅仅是 ksh)中的引号设置逐字符解析标志,以防止发生字符串拆分和通配(对于单引号,还可以防止各种其他操作如出色地)。因此,当您在 POSIX-y shell 中运行 PARAM="VALUE WITH SPACE" 时,它只会变为 PARAM=VALUE WITH SPACE,但是由于能够将字符串拆分为多个参数而抑制了空格(因此在 JSON 中,它会变成 ["PARAM=VALUE WITH SPACE"] ["PARAM=VALUE", "WITH", "SPACE"] 就像没有任何引号一样)。
【解决方案2】:

好的,感谢您的 cmets 关于 set -x 的解释,我确实错误地解释了它,我得到它实际上与 command \"foo bar\" 一起工作,除了 set 输出表明它正确传递用括号括起来的“foo bar”作为命令参数.

事实证明,我的实际问题是参数值本身的语法。 供将来参考,当传递的值开始有空格时,ksh 中的 expdp 命令语法是正确的(在这种情况下,用户 ID 为 sysdba):

expdp USERID=\"sys/password@SID as sysdba\" DIRECTORY=EXPDP DUMPFILE=HR.COUNTRIES.dmp TABLES=HR.COUNTRIES ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-22
    • 2019-12-05
    • 1970-01-01
    相关资源
    最近更新 更多