我正在编写一个python程序,它将参数传递给shell脚本。
这是我的python代码:
import subprocess
Process=subprocess.Popen('./copyImage.sh %s' %s str(myPic.jpg))
而我的“copyImage.sh”:
#!/bin/sh
cp /home/pi/project/$1 /home/pi/project/newImage.jpg
我可以毫无问题地在终端上运行脚本。但是当执行python代码时,终端返回了"NameError: name 'myPic' is not defined"
。
如果我将语法更改为
Process=subprocess.Popen('./copyImage.sh %s' %s "myPic.jpg")
然后终端返回"OSError: [Errno 2] No such file or directory"
。
我跟着这个:Python: executing shell script with arguments(variable), but argument is not read in shell script但它没有帮助。
subprocess
模块需要一个参数列表,而不是一个以空格分隔的字符串。你尝试的方式导致python寻找一个名为"copyImage.sh myPic.jpg"
的程序,并且没有参数调用它,而你想找一个名为copyImage.sh
的程序并用一个参数调用它。
subprocess.check_call(['copyImage.sh', 'myPic.jpg'])
我还想提一下,因为你的脚本只是在shell中调用copy,你应该切掉中间人并直接使用python的shutil.copy
。它比为此任务运行子进程更合适。
使用os.system调用是这样的:
例:
os.system('myshellscript1 ' + arg1 + ' ' + arg2)
安全可靠的方式是:
subprocess.Popen(["./copyImage.sh", "myPic.jpg"])
您的第一次尝试失败,因为字符串文字需要Python中的引号。第二个失败是因为Popen默认不运行shell(你链接的问题设置Shell=true
这样做,但它很脆弱而且很糟糕)。
虽然你有2个答案显示如何使用subprocess
和参数的迭代,我建议采用其中一种方式,为了完整性你可以使用包含完整命令的字符串,如果你指定shell=True
,但是你负责所有引用和所有类似的参数。
Process=subprocess.Popen('./copyImage.sh %s' % shlex.quote("myPic.jpg"), shell=True)
请注意,除了添加shell=True
之外,我通过shlex.quote
传递参数,让它处理转义任何特殊字符,以使文件来自用户输入时更安全一些,否则它可能包含;
和另一个要运行的命令,例如。像myPic.jpg; rm -rf ~
这样的输入会在执行时导致坏事发生。
如果未指定shell=True
,则subrpocess模块实际上将查找名为copyImage.sh myPic.jpg
的可执行文件,其中包含空格和两个单词作为要运行的可执行文件的名称。
另外两个注释,对于python 2而不是shlex.quote
使用pipes.quote
。此外,上面的shell脚本不引用其参数,因此不能使用带空格或其他特殊字符的名称。应修改它以引用其变量(即always a good idea):
#!/bin/sh
cp /home/pi/project/"$1" /home/pi/project/newImage.jpg
脚本略有不同:
#!/bin/bash
printf 'Arg 1 is: %s\n' "$1"
我们可以看到这项工作如下:
subprocess.check_call("./demoScript.sh %s" % shlex.quote("This has ; bad stuff"), shell=True)
它在stdout
上产生以下输出
Arg 1 is: This has ; bad stuff