【问题标题】:FastScripts MacOSX app: strange stdin behavior when calling subprocessed Python scriptsFastScripts MacOS 应用程序:调用子进程 Python 脚本时出现奇怪的标准输入行为
【发布时间】:2015-07-20 03:16:35
【问题描述】:

总结。为什么FastScripts application 会执行以下操作,是否有目的,我或 FastScripts 开发人员能否以某种方式修复/更改行为以不执行此操作? (否则我发现 FastScripts 是一个极好的应用程序。我运行的是 MacOS 10.9.5。)

详情。

FastScripts 2.6.8 似乎将其运行的当前脚本的内容复制到stdin,用于在所述脚本中运行的任何子进程,如下面的命令行会话所示。这不仅很奇怪,而且在开发由 FastScripts 指令触发的软件时可能会造成严重的混乱。

我没有用非 Python 脚本测试过类似的行为,但我编写的多个独立 Python 程序的行为方式都相同。我将通过电子邮件将此问题的链接发送给 FastScripts 开发人员/技术支持。

以下演示了正确运行的脚本:

$ cat test_subprocess_stdin.py 
#!/usr/bin/env python
import subprocess
cmd1 = '/tmp/reprint_stdin.py            >/tmp/cmd1out.txt'
cmd2 = '/tmp/reprint_stdin.py </dev/null >/tmp/cmd2out.txt'
subprocess.Popen(cmd1, shell=True)
subprocess.Popen(cmd2, shell=True)
$ cat /tmp/reprint_stdin.py 
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
# from http://stackoverflow.com/a/17735803/605356
stdin_content_present = not sys.stdin.isatty()
if stdin_content_present:
    for line in sys.stdin:
        sys.stdout.write('stdin: ' + line)
$ ./test_subprocess_stdin.py 
$ cat /tmp/cmd1out.txt
$ cat /tmp/cmd2out.txt
$

但是,从 FastScripts 运行上述脚本时会发生奇怪的事情:

$ # <now running test_subprocess_stdin.py from FastScripts keyboard shortcut>
$ 
$ cat /tmp/cmd1out.txt 
stdin: #!/usr/bin/env python
stdin: import subprocess
stdin: cmd1 = '/tmp/reprint_stdin.py            >/tmp/cmd1out.txt'
stdin: cmd2 = '/tmp/reprint_stdin.py </dev/null >/tmp/cmd2out.txt'
stdin: subprocess.Popen(cmd1, shell=True)
stdin: subprocess.Popen(cmd2, shell=True)
$ cat /tmp/cmd2out.txt 
$ 
$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.9.5
BuildVersion:   13F1077
$ 

请注意,调用 os.system() 代替 subprocess.Popen() 会导致相同的异常行为。

出于某种原因,FastScripts 并且只有 FastScripts 似乎将它正在运行的脚本的内容(在上述情况下为test_subprocess_stdin.py)定向到被调用的任何(子)脚本的标准输入在顶级脚本/程序中。 (&lt;/dev/null 指示被调用的下标忽略标准输入。)这很奇怪,正因为如此,我花了很多开发和调试时间来发现为什么我的 FastScript 调用程序会中断。

【问题讨论】:

  • 我还没有看到来自FastScripts support team 的电子邮件回复。我刚刚又发了一封邮件。
  • fwiw,Daniel 立即回复了我的第二封电子邮件 answer below - 我怀疑我的第一封电子邮件被他的垃圾邮件过滤器捕获了,或者类似的。
  • 嗨,Johnny - 如果您想测试它,我有一个暂定的解决方法。它将 FastScripts 更改为“直接”运行 shell 脚本,而不是尝试自行将脚本内容复制到解释器。 red-sweater.com/fastscripts/FastScripts2.6.9b3.zip我很想知道这是否可以解决您的问题。
  • @danielpunkass 谢谢,我测试了 2.6.9b3 并没有看到症状,但后来我重新安装了 2.6.8 (在 CleanMyMac 2 卸载后)......和有问题的症状似乎也从这个原本破碎的环境中消失了。即,2.6.8 现在似乎也“工作”了。诚然,我没有彻底调查。唔。也许我没有正确运行该过程,但我保留了我的 Python 单元测试,以便(希望)可靠地复制测试。想法?
  • 嗨约翰尼 - 我不确定是什么会导致 2.6.8 也“工作”......这看起来确实令人惊讶。根据我对正在发生的事情的理解,我认为从 2.6.8 运行时,它总是会将标准输入复制到子进程中。

标签: python macos shell keyboard-shortcuts stdin


【解决方案1】:

感谢您提出这个有趣的问题。我已经下载并确认了您看到的相同行为,目前正在尝试理解它。

FastScripts 运行 shell 脚本的方式是从 #! (shebang) 脚本中要运行的工具的名称行,然后简单地运行该工具,将脚本文件的内容作为标准输入提供给正在运行的工具。因此,例如在您的示例中,它将运行:

/usr/bin/env python

将文件内容作为标准输入。

据我所知,这是调用 shell 工具以运行任意基于脚本的命令的一种非常传统的方式。那么为什么 FastScripts 的行为不同于例如从命令行运行该工具?我不知道。

显然有据可查的是,子进程确实继承了它们的父进程,例如stdin (https://unix.stackexchange.com/questions/58252/what-sets-a-childs-stderr-stdout-and-stdin),所以当 env 运行 python 而 python 运行子进程调用时,标准输入应该保持活动状态并不神秘。

我想到的问题是,在直接从命令行运行脚本的情况下会发生什么不同?我不知道 shell 脚本执行的标准实现是否做了一些特殊的事情来防止将标准输入传播到脚本本身。我得调查一下。

【讨论】:

  • 我查看了 Apple 的 bash 源代码,以更好地了解发生了什么:opensource.apple.com/source/bash/bash-94.1.2 很明显,在 shell 的情况下,它并没有做类似的诡计我所做的,因为它依赖于系统内核能够直接运行 shell 脚本。我不确定这是否总是正确的,或者我是否需要在某些系统版本上继续使用我的技巧,但我至少应该能够切换到让内核也直接运行 shell 脚本。这有望解决您遇到的问题。
猜你喜欢
  • 2018-02-14
  • 2016-06-06
  • 2020-10-22
  • 2021-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多