【问题标题】:How do I embed my shell scanning-script into a Python script?如何将我的 shell 扫描脚本嵌入到 Python 脚本中?
【发布时间】:2019-10-28 08:56:13
【问题描述】:

我一直在使用以下 shell 命令从名为scanner_name 的扫描仪中读取图像并将其保存在名为file_name 的文件中

scanimage -d <scanner_name> --resolution=300 --format=tiff --mode=Color 2>&1 > <file_name>

这对我的目的来说效果很好。 我现在正试图将它嵌入到 python 脚本中。我需要像以前一样将扫描的图像保存到文件中,并将任何标准输出(比如错误消息)捕获到字符串中

我试过了

    scan_result = os.system('scanimage -d {} --resolution=300 --format=tiff --mode=Color 2>&1 > {} '.format(scanner, file_name))

但是当我在循环中运行它时(使用不同的扫描仪),扫描之间存在不合理的长时间延迟,并且直到下一次扫描开始时才会保存图像(文件被创建为空文件并且未填充直到下一个扫描命令)。这一切都是用scan_result=0,即表示没有错误

子进程方法run()已经推荐给我了,我试过了

with open(file_name, 'w') as scanfile:

    input_params = '-d {} --resolution=300 --format=tiff --mode=Color 2>&1 > {} '.format(scanner, file_name)
    scan_result = subprocess.run(["scanimage", input_params], stdout=scanfile, shell=True)

但这会将图像保存为某种不可读的文件格式

关于可能出现什么问题的任何想法?或者我还可以尝试什么来保存文件并检查成功状态?

【问题讨论】:

  • 你不能使用subprocess.run([... list ...], shell=True),它要么用shell=True传递一个单一的sting,要么传递一个没有shell的令牌列表。

标签: python shell scanning


【解决方案1】:

subprocess.run() 绝对比os.system() 更受欢迎,但它们都不支持并行运行多个作业。您将需要使用 Python 的 multiprocessing 库之类的东西来并行运行多个任务(或者在基本的 subprocess.Popen() API 之上自己痛苦地重新实现它)。

您对如何运行subprocess.run() 也有一个基本的误解。你可以传入一个字符串和shell=True,或者一个令牌列表和shell=False(或者根本没有shell关键字;False是默认值)。

with_shell = subprocess.run(
    "scanimage -d {} --resolution=300 --format=tiff --mode=Color 2>&1 > {} ".format(
        scanner, file_name), shell=True)

with open(file_name) as write_handle:
    no_shell = subprocess.run([
        "scanimage", "-d", scanner, "--resolution=300", "--format=tiff",
            "--mode=Color"],  stdout=write_handle)

您会注意到后者不支持重定向(因为这是一个 shell 功能),但这在 Python 中相当容易实现。 (我去掉了标准错误的重定向——你真的希望错误消息保留在 stderr 上!)

如果您有一个更大的工作 Python 程序,那么与 multiprocessing.Pool() 集成应该不会很难。如果这是一个小的独立程序,我建议你完全剥离 Python 层,使用 xargs 或 GNU parallel 之类的东西来运行数量上限的并行子进程。

【讨论】:

【解决方案2】:

我怀疑问题是您正在打开输出文件,然后在其中运行subprocess.run()。这是没有必要的。最终结果是,您通过 Python 打开文件,然后让命令通过操作系统打开文件再次,然后通过 Python 关闭文件。

只需运行子进程,并让scanimage 2&gt;&amp;1&gt; filename 命令创建文件(就像在命令行中直接运行scanimage 一样。)

我认为subprocess.check_output() 现在是捕获输出的首选方法。

from subprocess import check_output
# Command must be a list, with all parameters as separate list items
command = ['scanimage', 
           '-d{}'.format(scanner), 
           '--resolution=300', 
           '--format=tiff', 
           '--mode=Color', 
           '2>&1>{}'.format(file_name)]

scan_result = check_output(command)
print(scan_result)

但是,(runcheck_outputshell=True 是一个很大的安全风险......特别是如果input_params 从外部进入 Python 脚本。人们可以传入不需要的命令,并让它们在具有脚本权限的 shell 中运行。

有时,shell=True 是操作系统命令正常运行所必需的,在这种情况下,最好的建议是使用实际的 Python 模块与扫描仪交互 - 而不是让 Python 将操作系统命令传递给操作系统。

【讨论】:

  • 如果传递令牌列表和shell=False,则不能使用重定向等shell 功能。
猜你喜欢
  • 2015-04-14
  • 2021-05-18
  • 2011-06-01
  • 1970-01-01
  • 2022-01-12
  • 1970-01-01
  • 2017-03-16
  • 2020-10-02
  • 1970-01-01
相关资源
最近更新 更多