【问题标题】:Bash command substitution executing before earlier code在早期代码之前执行 Bash 命令替换
【发布时间】:2015-07-01 16:24:01
【问题描述】:
ssh -i "path/to/my/key.key" ip.ip.ip.ip "mkdir a/a; sql 'query;' > a/a/file.txt; if [ -f a/a/file.txt ]; then if [ $(wc -l a/a/file.txt) -ge 2 ]; then echo 'done'; fi; fi; exit"

通过 ssh 连接后,我基本上是在创建一个目录,将 sql 查询写入文件。如果该文件存在,则检查其字数是否大于 1。如果字数大于 1,则回显完成,然后退出。

但是,我收到此错误:

wc: a/a/file.txt open: No such file or directory

似乎命令替换 $(wc -l a/a/file.txt) 是首先执行的(至少在 sql 查询之前),因此该文件尚未创建。有什么方法可以强制它按照其写入的顺序执行,还是有更好的方法来做到这一点?

【问题讨论】:

  • 是的,你有双引号中的字符串,所以变量/命令替换/等。一切都发生在呼叫方。您需要单引号或转义扩展以避免这种情况。
  • wc -l file 的输出也不能直接用于-gt 测试,它包含文件名。使用wc -l <file 来避免这种情况。
  • -f 测试不是必需的;一旦sql 返回,该文件就保证存在,因为shell 在执行sql 之前创建它。

标签: bash shell unix terminal


【解决方案1】:

在调用ssh 之前,您需要保护命令替换不被扩展;您可以将整个命令用单引号括起来,或者简单地将$ 转义在双引号中(如图所示)。 (为清楚起见插入了换行符;它们不是必需的,但可以根据需要使用。)

ssh -i "path/to/my/key.key" ip.ip.ip.ip "mkdir -p a/a
 sql 'query;' > a/a/file.txt
 [[ \$(wc -l < a/a/file.txt) -ge 2 ]] && echo 'done'"

-f 测试是不必要的; shell 在运行sql 之前创建文件,无论命令是否产生任何输出,该文件都将存在。 exit 也是不必要的;无论如何,只要执行最后一个命令,shell 就会退出。

完全避免命令替换的一种(hacky?)方法是简单地尝试使用read从文件中读取两行:

ssh ... "mkdir -p a/a
 sql 'query;' > a/a/file.txt
 { read && read; } < a/a/file.txt && echo 'done'"

【讨论】:

  • 我正在处理一个有缺陷的 sql 版本,这就是为什么我必须首先进行这些检查。该查询似乎有 3 种类型的错误。 2 种类型将一行错误消息写入文件,这就是为什么我检查它是否至少有两行。第三种类型退出而不写入文件,这就是我检查文件是否存在的原因。
  • 如果文件根本不存在,那不是sql的原因; shell 在相关命令运行之前创建重定向目标。单行错误信息确实需要行数;我会修改我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-04
  • 1970-01-01
  • 2020-11-10
  • 1970-01-01
  • 2017-12-20
相关资源
最近更新 更多