0

I've seen similar questions (e.g. Running a command in a new Mac OS X Terminal window ) but I need to confirm this command and its expected behavior in a mac (which I don't have). If anyone can run the following in Python 3 Mac:

import subprocess, os
def runcom(bashCommand):
     sp = subprocess.Popen(['osascript'], stdin=subprocess.PIPE, stderr=subprocess.PIPE)
     sp.communicate('''tell application "Terminal"\nactivate\ndo script with command "{0} $EXIT"\nend tell'''.format(bashCommand))

runcom('''echo \\"This is a test\\n\\nThis should come two lines later; press any key\\";read throwaway''')
runcom('''echo \\"This is a test\\"\n\necho \\"This should come one line later; press any key\\";read throwaway''')
runcom('''echo \\"This is testing whether I can have you enter your sudo pw on separate terminal\\";sudo ls;\necho \\"You should see your current directory; press any key\\";read throwaway''')

Firstly, and most basically, is the "spawn new terminal and execute" command correct? (For reference, this version of the runcom function came from this answer below, and is much cleaner than my original.)

As for the actual tests: the first one tests that internal double escaped \\n characters really work. The second tests that we can put (unescaped) newlines into the "script" and still have it work just like semicolon. Finally, the last one tests whether you can call a sudo process in a separate terminal (my ultimate goal).

In all cases, the new terminal should disappear as soon as you "press any key". Please also confirm this.

If one of these doesn't work, a correction/diagnosis would be most appreciated. Also appreciated: is there a more pythonic way of spawning a terminal on Mac then executing a (sudo, extended) bash commands on it?

Thanks!

Community
  • 1
  • 1
scarlet
  • 137
  • 7

2 Answers2

1

I don't have Python 3, but I edited your runcom function a little and it should work:

def runcom(bashCommand):
    sp = subprocess.Popen(['osascript'], stdin=subprocess.PIPE, stderr=subprocess.PIPE)
    sp.communicate('''tell application "Terminal"\nactivate\ndo script with command "{0} $EXIT"\nend tell'''.format(bashCommand))
icktoofay
  • 126,289
  • 21
  • 250
  • 231
1

[...] its expected behavior [...]

This is hard to answer, since those commands do what I expect them to do, which might not be what you expect them to do.

As for the actual tests: the first one tests that internal double escaped \n characters really work.

The \\n with the doubled backslash does indeed work correctly in that it causes echo to emit a newline character. However, no double quotes are emitted by echo.

The second tests that we can put (unescaped) newlines into the "script" and still have it work just like semicolon.

That works also.

Finally, the last one tests whether you can call a sudo process in a separate terminal (my ultimate goal).

There is no reason why this should not work also, and indeed it does.

In all cases, the new terminal should disappear as soon as you "press any key". Please also confirm this.

That will not work because of several reasons:

  • read in bash will by default read a whole line, not just one character
  • after the script you supply is executed, there is no reason for the shell within the terminal to exit
  • even if the shell would exit, the user can configure Terminal.app not to close a window after the shell exits (this is even the default setting)

Other problems:

  • the script you supply to osascript will appear in the terminal window before it is executed. in the examples above, the user will see every "This is a test [...]" twice.
  • I cannot figure out what $EXIT is supposed to do
  • The ls command will show the user "the current directory" only in the sense that the current working directory in a new terminal window will always be the user's home directory
  • throwaway will not be available after the script bashCommand exits

Finally, this script will not work at all under Python 3, because it crashes with a TypeError: communicate() takes a byte string as argument, not a string.

Also appreciated: is there a more pythonic way of spawning a terminal on Mac [...]

You should look into PyObjC! It's not necessarily more pythonic, but at least you would eliminate some layers of indirection.

  • Very enlightening, thanks! And nice catch with the `TypeError`! Followup: 1. is there a way to make the commands not show up in the popup terminals before they are executed? 2. $EXIT is supposed to force the newly spawned Terminal to exit after completing the bashCommand. You say the Terminal does not close, however :( Is there a way to make it do so? Thank you very much for your level of detail. – scarlet Sep 25 '11 at 01:53
  • @scarlet: i still don't get the $EXIT… you can't just villy-nilly stick some invented word somewhere and expect it to do anything. where did you get that from? maybe it's half of a solution you found? –  Sep 27 '11 at 11:44
  • That's probably it, yeah. As an update, I found out that running something in osascript "with administrator privileges" pops up a graphical login, thereby obviating the need for a terminal. It's one of those silly things you don't realize unless you actually have a mac :( Updated code is now `process.communicate( '''do shell script "{0}" with administrator privileges'''.format(bashCommand).encode() )`, more or less. – scarlet Sep 28 '11 at 10:03