2

Summary. Why does the FastScripts application do the following, is it purposeful, and can I or FastScripts developers somehow fix/change the behavior to not do this? (I otherwise find FastScripts to be a superb application. I'm running MacOS 10.9.5.)

Details.

FastScripts 2.6.8 appears to copy the content of the current script its running to stdin for any subprocess that runs in said script, as demonstrated by the command-line session below. Not only is this just plain weird, it can cause significant confusion when developing software triggered by FastScripts directives.

I've not tested similar behavior with non-Python scripts, but multiple independent Python programs I've written all behave the same way. I'll be emailing a link to this question to the FastScripts developers/technical support.

The following demonstrates the scripts running properly:

$ 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
$

However, strange stuff happens when running the above script(s) from 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
$ 

Note that calling os.system() in place of subprocess.Popen() causes same, anomalous behavior.

For some reason, FastScripts and only FastScripts seems to direct the content of the script it's running (in the above case, test_subprocess_stdin.py) to the stdin of any (sub) script that gets called within the toplevel script/program. (The </dev/null directs the called subscript to ignore stdin.) This is strange, and because of this, it took a lot of my development+debugging time to discover why my FastScript-called programs were breaking.

Johnny Utahh
  • 2,389
  • 3
  • 25
  • 41
  • I've not yet seen an email reply from the [FastScripts support team](http://www.red-sweater.com/support). I've sent another email just now. – Johnny Utahh May 17 '15 at 21:57
  • fwiw, Daniel responded right away to my second email with the [answer below](http://stackoverflow.com/a/30307762/605356) - I suspect my first email got caught in his spam filter, or some such. – Johnny Utahh May 18 '15 at 15:58
  • Hi Johnny - I have a tentative fix for this if you'd like to test it. It changes FastScripts to running shell scripts "directly" rather than trying to copy the script content to the interpretor on its own. http://www.red-sweater.com/fastscripts/FastScripts2.6.9b3.zip I'll be curious to hear whether this fixes the behavior for you. – danielpunkass May 18 '15 at 16:31
  • @danielpunkass Thanks, I tested 2.6.9b3 and did not see the symptoms, but then I re-installed (after a CleanMyMac 2 de-install) of 2.6.8... and the problematic symptoms seem to have also vanished from this originally-broken environment. ie, 2.6.8 now also seems to "work." Granted, I haven't exhaustively investigated. Hmm. Maybe I'm not running the procedure correctly, but I kept my Python unittests around in order to (hopefully) reliably duplicate the tests. Thoughts? – Johnny Utahh May 18 '15 at 19:26
  • Hi Johnny - I'm not sure what would cause 2.6.8 to also "work" ... that does seem surprising. Based on my understanding of what was going on I would think it will always have the stdin copied to the subprocess when running from 2.6.8. – danielpunkass May 18 '15 at 20:54

1 Answers1

1

thanks for raising this interesting question. I have downloaded and confirmed the same behavior that you see, and am currently trying to make sense of it.

The way FastScripts runs shell scripts is to interpret from the #! (shebang) line in the script the name of the tool to run, and then simply running that tool, providing the content of the script file as standard input to the tool being run. So for example in your example, it would be running:

/usr/bin/env python

With the contents of the file as the standard input.

As far as I know this is a pretty conventional way to invoke a shell tool for running arbitrary script-based commands. So why does FastScripts behave differently than e.g. running the tool from the command line? I don't know.

It is apparently well-documented that child processes do inherit their parent process's e.g. stdin (https://unix.stackexchange.com/questions/58252/what-sets-a-childs-stderr-stdout-and-stdin), so it's not mysterious that when env runs python and in turn python runs the subprocess call, the standard input should remain active.

The question to my mind is what is happening differently in the case of running the script directly from the command line? I don't know if the standard implementation of shell script execution does something special to prevent propagating stdin to the script itself. I'll have to look into this.

Community
  • 1
  • 1
danielpunkass
  • 17,527
  • 4
  • 24
  • 38
  • I took a look at Apple's source code for bash, to get a better idea of what is going on: http://opensource.apple.com/source/bash/bash-94.1.2/ There it became clear that in the shell's case, it is not doing similar trickery to what I do, because it counts on the system Kernel being able to run shell scripts directly. I'm not sure if this was always true or if I need to keep doing my tricks on certain system releases, but I should at least be able to switch to letting the kernel run the shell script directly as well. That would hopefully address the problem you are seeing. – danielpunkass May 18 '15 at 16:07