【问题标题】:using Python to send subprocess commands with escape characters使用 Python 发送带有转义字符的子进程命令
【发布时间】:2018-04-23 23:44:19
【问题描述】:

我正在使用一个 python 脚本,它使用 subprocess 将命令传递给终端。我传递的部分命令涉及包含括号的路径。 Python 可以很好地处理带括号的字符串,但是终端当然不会在没有转义字符的情况下处理这些字符串。

我正在尝试通过将字符串输入子进程来将变量传递给命令行程序,但这里有一个重现错误的简单示例:

import subprocess

path = '/home/user/Desktop/directory(2018)'
command_str =  'rmdir ' + path
print (subprocess.run(command_str))

这给了我这个错误:

Traceback (most recent call last):
  File "ex.py", line 7, in <module>
    print (subprocess.run(command_str))
  File "/usr/lib/python3.6/subprocess.py", line 403, in run
    with Popen(*popenargs, **kwargs) as process:
  File "/usr/lib/python3.6/subprocess.py", line 709, in __init__
    restore_signals, start_new_session)
  File "/usr/lib/python3.6/subprocess.py", line 1344, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'rmdir /home/user/Desktop/directory(2018)': 'rmdir /home/user/Desktop/directory(2018)'

当我使用转义字符直接将其写入终端时,效果很好。

$ rmdir /home/user/Desktop/directory\(2018\)

但在 Python 中,当我尝试在调用子进程之前向字符串中添加转义字符时:

command_str = command_str.replace('(','\(')
command_str = command_str.replace(')','\)')

我得到与以前相同的错误,因为与print 不同,子进程字符串添加了第二个转义字符,该转义字符被传递到终端。

Traceback (most recent call last):
  File "ex.py", line 7, in <module>
    print (subprocess.run(command_str))
  File "/usr/lib/python3.6/subprocess.py", line 403, in run
    with Popen(*popenargs, **kwargs) as process:
  File "/usr/lib/python3.6/subprocess.py", line 709, in __init__
    restore_signals, start_new_session)
  File "/usr/lib/python3.6/subprocess.py", line 1344, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'rmdir /home/user/Desktop/directory\\(2018\\)': 'rmdir /home/user/Desktop/directory\\(2018\\)'

有没有办法修复这个特定的错误?要么用replacesubprocess.run 做一些不同的事情吗? (我不是在寻找更好的方法来删除目录。)谢谢。

【问题讨论】:

    标签: python replace terminal subprocess escaping


    【解决方案1】:

    Python 实现了rmrmdir,因此无需调用进程。一般来说,如果您想跳过对subprocess 中的命令的shell 处理,请不要使用shell。

    import subprocess
    
    path = '/home/user/Desktop/directory(2018)'
    command =  ['rmdir', path]
    print (subprocess.run(command, shell=False))
    

    shell 将命令行分解为参数列表。您可以自己构建该列表并完全跳过 shell。

    【讨论】:

    • 构建参数列表并将 shell 设置为 False 解决了这个问题!感谢您的提示
    • 这仍然调用一个子进程(可能是/bin/rmdir),所以我认为说“Python 实现 rm 和 rmdir”是一种误导。不值得一票,但我想值得一提。
    • @wim - python 实际上实现了rm(参见os.remove)和rmdir(参见shutil.rmtree)功能。您是否担心这些命令有比 python 等效的更多选项?问题是关于转义字符,这就是我回答的问题。
    • 我的意思是你说你不需要调用进程,然后你显示调用进程的代码,它读起来不好/令人困惑。你不需要告诉我shutil.rmtree 是 Python rmdir,因为我已经在 4 小时前发布了这个答案...... ;)
    • 我说你不​​需要rm 命令的子进程,但通常这就是你解决问题的方法。我认为 OP 有更多的用例——这是一个玩具例子——我是对的。我不觉得它最令人困惑。 “一般”意味着我指的是更一般的解决方案。
    【解决方案2】:

    不要使用子进程,也不必担心 shell 转义。使用stdlib的shutil提供的高级文件操作API:

    import shutil
    shutil.rmtree('/home/user/Desktop/directory(2018)')
    

    【讨论】:

    • 所以我正在尝试使用具有更复杂命令的脚本,该命令从终端运行ffmpeg。上面带有rmdir 的代码是重现错误的示例。我会在问题中澄清这一点。谢谢!
    猜你喜欢
    • 2013-04-27
    • 1970-01-01
    • 1970-01-01
    • 2012-05-22
    • 1970-01-01
    • 2015-07-14
    • 1970-01-01
    • 2019-11-24
    • 2012-05-16
    相关资源
    最近更新 更多