【问题标题】:bash command not running through pythonbash命令未通过python运行
【发布时间】:2020-11-18 15:50:13
【问题描述】:

我有以下方法:

def _run_command(bash_command: str) -> str:
    """
    Run a bash command.

    Args:
        bash_command: command to be executed.
    """
    logging.info(f"Running {bash_command}.")
    process = subprocess.Popen(bash_command.split(), stdout=subprocess.PIPE)
    output, error = process.communicate()
    if error is not None:
        logging.exception(f"Error running command: {bash_command}")
        raise ValueError(error)

    return str(output)

我用来通过 Python 运行 shell 命令。它似乎适用于大多数情况,除了这个:

command = f'find {self._prefix} -name "*.txt" -type f -delete'
output = self._run_command(command)

其中self._prefix 是一个路径,例如/opt/annotations/。我希望这个命令会删除该路径内的所有 txt 文件,这不会发生。但是,如果我直接在终端中运行此命令find /opt/annotations/ -name "*.txt" -type f -delete,则所有内容都会按预期删除。所以我想知道我是否在这里遗漏了什么。

日志显示了 expect 命令,但是,txt 没有被删除:

2020-11-18 19:07:47 fm-101 root[10] INFO Running find /opt/annotations/ -name "*.txt" -type f -delete.

【问题讨论】:

  • /opt/annotations\opt\annotations!在 POSIX 上,这些是完全不同的路径。此外,你不能只在空格上split() 一个 shell 命令,从长远来看,你一定会遇到麻烦。但是如果路径正确且没有空格,您的代码确实可以工作。
  • 要添加到@KonradRudolph 所写的内容,您应该使用os.path 进行路径操作,以便它适用于任何操作系统。当您运行上述命令时,output 变量中还有什么内容?
  • @sedavidw 输出返回 emtpy。
  • @KonradRudolph,谢谢,路径是错字。它总是/opt/annotations/
  • 顺便说一句,如果您采用shlex.split() 方法或使用真正的shell (shell=True),请确保在使用f-strings 生成shell 命令时,使用shlex.quote()生成您的价值观的版本,这些版本将转义回其原始/预期内容。因此,这里的示例可能是 f'find {shlex.quote(self._prefix)} -name "*.txt" -type f -delete')

标签: python shell subprocess


【解决方案1】:

问题在于引号。您没有与"*.txt" 匹配的文件,而只有与*.txt 匹配的文件。

将您的命令显式作为列表传递,而不是尝试从字符串生成列表,以避免这个问题和其他问题:

def _run_command(command_argv: list) -> str:
    logging.info(f"Running {command_argv}.")
    process = subprocess.Popen(command_argv, stdout=subprocess.PIPE)
    output, error = process.communicate()
    if error is not None:
        logging.exception(f"Error running command: {bash_command}")
        raise ValueError(error)
    return str(output)

_run_command(['find', str(self._prefix), '-name', '*.txt', '-type', 'f', '-delete'])

如果您坚持将参数作为字符串,请使用 shlex.split() 来获得类似 POSIX sh(而非 bash)的引用值处理:

def _run_command(shell_command: str) -> str:
    """
    Run a shell command, but without actually invoking any shell

    Args:
        shell_command: command to be executed.
    """
    logging.info(f"Running {shell_command}.")
    process = subprocess.Popen(shlex.split(shell_command), stdout=subprocess.PIPE)
    output, error = process.communicate()
    if error is not None:
        logging.exception(f"Error running command: {shell_command}")
        raise ValueError(error)

    return str(output)

...但这仅解决了引号删除的特定问题;它不会使操作在任何其他方面与 shell 兼容。

【讨论】:

    猜你喜欢
    • 2014-10-30
    • 1970-01-01
    • 2019-04-07
    • 1970-01-01
    • 2017-09-08
    • 2021-03-20
    • 2019-02-22
    • 2014-04-07
    • 2012-10-23
    相关资源
    最近更新 更多