Archives | Categories

Call External Command and Bash Quote

Table of Contents

<2014-11-21 Fri>

1. 问题

今天图方便在 python 代码里执行一段 bash,写出了类似代码:

ctx.run("""bash -c "
for file in $(find . -type p); do
  rm $file
done
"
""")

ctx.runInvoke 里的 run,类似 os.system 。

之后就 bash 就一个劲的抱怨 syntax error ,各种方法调了近一个小时都没解决,下班路上忽然想到 ctx.run(cmd_string) 这种 API 本身应该就是调用 sh 来执行 cmd_string 的,由于 -c 后面用了 double quote,bash 看到的 cmd string 是已经被 sh 展开过的了……

回家确认了下 Invoke的源码 , ctx.run 果然是调用的 shell……,于是把 -c 后面的 double quote 改成 signle quote 避免 shell 做提前的展开解决。

Note
从 invoke 代码看,调用 ctx.run 是指定 pty=True 可确保调用的 shell 是 bash,此时可以直接用的 cmd_string 不用 bash -c 来确保所用 shell 是 bash 。

2. 结论

  • 无论什么语言什么库,调用外部程序的函数一般分三类:
    • 有明确参数指定是否在 shell 中执行 cmd,依照调用时给定 shell 参数为 true 或 false 分别落入后面两种情况;
    • 其参数是一个字符串,如 system(3),这种一般是 fork(2) 一个进程,之后 exec(2) /bin/sh, 并同时将字符串传给 sh 来执行的,所以 sh 会对参数做展开然后执行;
    • 其参数是一个或多个字符串数组,如 python 的 os.spawnv 等,这种情况是一般是调用 fork(2) 后调用 exec(2) 直接执行给定的可执行文件,所以参数在传给可执行文件之前不会发生变化。
  • bash -c 后面的 command_string 一般情况下都是不期望它被展开的,所以首选 Single Quote

3. Discuss and Comment

Have few questions or feedback? Feel free to send me(killian.zhuo📧gmail.com) an email!

Copyright © KDr2, SOME RIGHTS RESERVED UNDER CC BY-NC 4.0.

Built with Emacs 28.2 (Org mode 9.5.5).

Last updated: 2022-01-28 Fri 13:42.