首页 > 解决方案 > 命令在 bash 终端中工作,但在 Python subprocess.Popen() 中不工作;得到一个'路径必须在表达式之前:'%p'错误

问题描述

我正在尝试查找最近修改过的文件的位置。在 bash 中,您可以通过

 find /media/tiwa/usb/ -not -path '*/\.*' -type f -printf '%T@ %p\n' 2> >(grep -v 'Permission denied' >&2) | sort -k1,1nr | head -1`

确实,在我的系统上,这会返回

1527379702.1060795850 /media/tiwa/usb/hi.txt

我打算获取此命令的输出(在 Python 中),将其拆分为第一个空格,然后解析文件路径(是的,我可以使用awk,但无论如何都会抛出相同的错误)。所以我做了

import subprocess
bashCommand = "find /media/tiwa/usb/ -not -path '*/\.*' -type f -printf '%T@ %p\n' 2> >(grep -v 'Permission denied' >&2) | sort -k1,1nr | head -1"
process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE)
output, error = process.communicate()
print(output)

但这打印出来

find: paths must precede expression: `%p'

转义反斜杠似乎也无济于事。

是什么导致了这个问题,我该如何解决?

标签: pythonlinuxbashsubprocess

解决方案


你有一个完整的 shell 命令行,而不仅仅是一个命令加上它的参数,这意味着你需要使用该shell=True选项而不是(错误地)将字符串拆分为多个字符串。(Python 字符串拆分不等同于 shell 的分词,后者更加复杂和复杂。)此外,由于您的命令行包含bash-specific 功能,因此您需要明确Popen使用/bin/bash,而不是默认使用/bin/sh.

import subprocess
bashCommand = "find /media/tiwa/usb/ -not -path '*/\.*' -type f -printf '%T@ %p\n' 2> >(grep -v 'Permission denied' >&2) | sort -k1,1nr | head -1"
path_to_bash = "/bin/bash"  # or whatever is appropriate
process = subprocess.Popen(bashCommand, 
                           stdout=subprocess.PIPE, 
                           shell=True,
                           executable=path_to_bash)
output, error = process.communicate()
print(output)

(但是,使用它os.walk()来获取每个文件,并用于os.stat()获取每个相关文件的修改时间,并且只保留迄今为止找到的最新文件,直到您检查了每个文件,它会更简单、更健壮。

import os
newest = (0, "")
for (dir, subdirs, fname) in os.walk("/media/tiwa/usb"):
    if fname.startswith(".") or not os.path.isfile(fname):
        continue
    mtime = os.stat(fname).st_mtime
    if mtime > newest[0]:
        newest = (mtime, fname)

也许

def names_and_times(d):
    for (_, _, fname) in os.walk(d):
        if fname.startswith(".") or not os.path.isfile(fname):
            continue
        yield (os.stat(fname).st_mtime), fname)

newest = max(names_and_times("/media/tiwa/usb"))

)

请记住,上述任何一种方法都只会返回一个具有最新修改时间的文件。


推荐阅读