为什么sh将shebang行解释为$()替换后的命令



我想使用Python脚本在我的zsh上安装,所以我从github进行无人值守安装。它使用sh -c下载安装脚本并使用sh:执行它

$ sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended

我想用subprocesspython中完成,所以我写了这个:

args = [
"sh",
"-c",
"$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
"",
"--unattended"
]
p = subprocess.run(args, check=True)

然而,我得到了错误,它说:

sh 1: #!/bin/sh: Not such file or directory

我想这意味着sh将shebang行解释为命令。它是如何发生的,如何避免?非常感谢!!!!

您的命令实际执行的操作;

  • 它在当前shell中运行curl
  • 然后它将引用的输出从curl传递到sh -c

也就是说,双引号内的字符串是curl已经获取的脚本文本。

Python代码实际所做的是不同的。

我会把它重构成

import requests
import subprocess
r = requests.get('https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh')
subprocess.run(['sh'], input=r.text, text=True)

或者,更确切地说,复制现有的命令,

subprocess.run(['sh', '-c', r.text, '', '--unattended'])

(如果您不想引入第三方库,requests在这里不是绝对必要的。

from urllib3 import PoolManager as u3
r = u3().request('GET', 'https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh')
subprocess.run(['sh', '-c', r.data, '', '--unattended'])

但正如您所看到的,只使用Python标准库有点麻烦。(

问题是您需要两轮评估:一轮是扩展命令替换,第二轮是将其视为shell代码。如果您在shell命令中使用了单引号,您也会看到同样的问题。

您可以显式添加eval:

args = [
"sh",
"-c",
"eval "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)""
"",
"--unattended"
]
p = subprocess.run(args, check=True)

最新更新