python执行带有多个参数的命令

时间:2018-03-23 13:19:48

标签: python

我想在Mac OS X计算机上使用Python运行以下命令:

openssl enc -aes-128-cbc -K $(echo -n 'blabla1' | xxd -p) -iv blabla2 -in /tmp/clair -nopad -out /tmp/crypte1 -d

以下是我的尝试:

clef = 'blabla1'
iv = 'blabla2'
arguments = ['openssl','enc', '-aes-128-cbc', '-K $(echo -n \'%s\' | xxd -p)' % clef ,'-iv' ,'%s' % iv,'-in', '/tmp/clair','-nopad','-out','/tmp/crypte1','-d']
execute = Popen(arguments, stdout=PIPE)
out, err = execute.communicate()

该命令在终端上工作正常,但我从Python脚本中收到错误:

unknown option '-K $(echo -n 'blabla1' | xxd -p)'

我已经尝试了几种python shell函数变体(例如os.system),但我在每种情况下都有问题。

2 个答案:

答案 0 :(得分:3)

在使用shell时,用户经常认为有很多事情是理所当然的。一些例子是:

  • 可变扩展(${var}
  • 输入/输出重定向(cmd > out < in
  • 管道(cmd1 | cmd2
  • 创建子shell($(cmd)

所有这些都是shell在将实际命令传递给系统之前设置的功能。 Python的subprocess模块不会自动为您执行任何操作,但它确实为您提供了模拟它们的工具。

您已正确地将输出重定向到管道以供Python进程选取。但是,由$(echo -n 'blabla1' | xxd -p)创建的子shell不会以没有shell的方式处理。有两个简单的解决方法。

  1. 快速而肮脏的解决方案是将整个命令行作为字符串传递给subprocess.Popen并设置shell=True

    execute = Popen("openssl enc -aes-128-cbc -K $(echo -n 'blabla1' | xxd -p) "
                    "-iv blabla2 -in /tmp/clair -nopad -out /tmp/crypte1 -d",
                    shell=True)
    

    这会将字符串传递给shell而不是直接传递给系统,从而使您可以访问shell期望的所有行为。这种方法存在重大安全问题,通常不建议使用。但是,这很容易,它会让你开始。

  2. 使用capturing通过subprocess.run $(... | ...)的输出直接在代码中实现xxd的便利性。这个更长,但从长远来看可能更加强大和便携。这当然是我在生产环境中选择的选项:

    from subprocess import Popen, run
    
    value = run(['xxd', '-p'], input='blabla1', universal_newlines=True).stdout
    execute = Popen(['openssl', 'enc', '-aes-128-cbc', '-K', value,
                     '-iv', 'blabla2', '-in', '/tmp/clair', '-nopad',
                     '-out', '/tmp/crypte1', '-d'])
    
  3. 由于您正在设置自己的管道,因此您无需再调用echo(您从未真正做过,xxd -p <<< 'blabla1'可以正常工作),并且-K需要是一个单独的论点。

答案 1 :(得分:0)

subprocess在参数"中添加引号"-K $(echo -n 'blabla1' | xxd -p)"。您可以通过

进行检查
print(subprocess.list2cmdline(execute.args))

<强>输出:

openssl enc -aes-128-cbc "-K $(echo -n 'blabla1' | xxd -p)" -iv blabla2 -in /tmp/clair -nopad -out /tmp/crypte1 -d