Launch gnu screen from python? - python

I tried executing a server daemon with gnu screen from subprocess call but it didn't even start
subprocess.call(["screen", "-dmS test ./server"])
I was told that running screen requires terminal, hence the reason why I can't simply execute it with call. Can you show me some piece of codes to do this?

Try
subprocess.call( ["screen", "-d", "-m", "-S", "test", "./server"] )
You need to break the argument string into separate arguments, one per string.
Here's the relevant quote from the subprocess docs:
On UNIX, with shell=False (default): In this case, the Popen class
uses os.execvp() to execute the child program. args should normally
be a sequence. A string will be treated as a sequence with the string
as the only item (the program to execute).
On UNIX, with shell=True: If args is a string, it specifies the
command string to execute through the shell. If args is a sequence,
the first item specifies the command string, and any additional items
will be treated as additional shell arguments.
So by default, the arguments are used exactly as you give them; it doesn't try to parse a string into multiple arguments. If you set shell to true, you could try the following:
subprocess.call("screen -dmS test ./server", shell=True)
and the string would be parsed exactly like a command line.

Related

How to open a new shell and run a command on it?

I want to run a code which opens a new shell and run the following command on it.
I tried those lines:
cmd_line = "env > help.txt"
subprocess.Popen(cmd_line, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
But its not opening a new shell.
The Popen method does not spawn a new instance of the shell. From the docs:
Execute a child program in a new process. On POSIX, the class uses os.execvp()-like behavior to execute the child program. On Windows, the class uses the Windows CreateProcess() function. The arguments to Popen are as follows.
The shell keyword argument does not open up a new shell for you, it runs the process under a new shell in the background before closing it. By default the she is sh
On POSIX with shell=True, the shell defaults to /bin/sh. If args is a string, the string specifies the command to execute through the shell. This means that the string must be formatted exactly as it would be when typed at the shell prompt. This includes, for example, quoting or backslash escaping filenames with spaces in them. If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional arguments to the shell itself. That is to say, Popen does the equivalent of: Popen(['/bin/sh', '-c', args[0], args[1], ...])
Under the hood python is "opening" a new shell, but it is hidden in the background and never shown explicitly to the user.
If you were looking to open a new shell for the user to interact with, you'd want to run the shell, and wait for it to terminate.
child_shell = Popen("/usr/bin/sh")
child_shell.wait()

What's the difference between subprocess.Popen("echo $HOME"... and subprocess.Popen(["echo", "$HOME"]

I cannot get it it's bash related or python subprocess, but results are different:
>>> subprocess.Popen("echo $HOME", shell=True, stdout=subprocess.PIPE).communicate()
(b'/Users/mac\n', None)
>>> subprocess.Popen(["echo", "$HOME"], shell=True, stdout=subprocess.PIPE).communicate()
(b'\n', None)
Why in second time it's just newline? Where argument are falling off?
The first argument to subprocess.Popen() tells the system what to run.
When it is a list, you need to use shell=False. It coincidentally happens to work as you hope in Windows; but on Unix-like platforms, you are simply passing in a number of arguments which will typically get ignored. Effectively,
/bin/sh -c 'echo' '$HOME'
which simply causes the second argument to not be used for anything (where I use single quotes to emphasize that these are just static strings).
In my humble opinion, Python should throw an error in this case. On Windows, too. This is an error which should be caught and reported.
(In the opposite case, where shell=False is specified but the string you pass in is not the name of a valid command, you will get an error eventually anyway, and it makes sense if you have even a vague idea of what's going on.)
If you really know what you are doing, you could cause the first argument to access subsequent arguments; for example
/bin/sh -c 'printf "%s\n" "$#"' 'ick' 'foo' 'bar' 'baz'
would print foo, bar, and baz on separate lines. (The "zeroth" argument - here, 'ick' - is used to populate $0.) But this is just an obscure corollary; don't try to use this for anything.
As a further aside, you should not use subprocess.Popen() if you just want a command to run. The subprocess.run() documentation tells you this in some more detail. With text=True you get a string instead of bytes.
result = subprocess.run('echo "$HOME"', shell=True,
text=True, capture_output=True, check=True)
print(result.stdout, result.stderr)
And of course, os.environ['HOME'] lets you access the value of $HOME from within Python. This also allows you to avoid shell=True which you usually should if you can.
In the documentation found on https://docs.python.org/2/library/subprocess.html#popen-constructor, if you look at the shell argument you will find
The shell argument (which defaults to False) specifies whether to use the shell as the program to execute. If shell is True, it is recommended to pass args as a string rather than as a sequence.
Which means that when you execute the second command it runs as echo and hence you get just a new line.
When you have shell=True, actual process that runs is the shell process i.e., think of it running /bin/sh -c on unix. The arguments you pass to Popen are passed as arguments to this shell process. So /bin/sh -c 'echo' '$HOME' prints newline and the second argument is ignored. So usually you should only use string arguments with shell=True.

How to viewthe actual command executed by "subprocess.check_call()"

I have a command as given below
subprocess.check_call(["C:\\Program Files\\operation.exe", "execute", "-af", "createrecord.xml", " -stuName", student,"-gender" ,gender], shell=True)
When I run this command manually it works fine. I believe that the subprocess.check_call() has not parsed the command properly (probably my mistake). How to view the output of subprocess.check_call().
I'd like to see the acutal command with arguments as called by subprocess.check_call()
NOTE - I don't want to see the return value of the command's execution. I only what to see how the command has been formatted by subprocess.check_call()
You should use the list form of the subprocess stuff only with (possibly implicit) shell=False and the string form only with shell=True.
The shell can only work with a command line which it then parses on its own. Without the shell, exec*() functions are usedm, which take the command line arguments in a separated way.
For Windows, this only holds up to a certain level, but it remains valid.

Checking Subprocesses in python

I'm trying to run one python program from another using subprocess. Here's the function I've got so far:
def runProcess(exe):
p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while(True):
retcode = p.poll() #returns None while subprocess is running
line = p.stdout.readline()
yield line
if(retcode is not None):
break
then i run:
for line in runProcess('python myotherprogram.py'): print line
but I get an OS error: no such file, but it doesn't tell me what file doesn't exist. It's baffling. Any suggestions? I can use the runProcess function for normal terminal commands, such as ls.
What doesn't exist is a single executable named python myotherprogram.py. To specify arguments, you need to provide a list consisting of the command and its argument, such as with runProcess(["python", "myotherprogram.py"]), or specify shell=True to the Popen constructor.
The relevant quote from the documentation:
args should be a sequence of program arguments or else a single
string. By default, the program to execute is the first item in args
if args is a sequence. If args is a string, the interpretation is
platform-dependent and described below. See the shell and executable
arguments for additional differences from the default behavior. Unless
otherwise stated, it is recommended to pass args as a sequence.
On Unix, if args is a string, the string is interpreted as the name or
path of the program to execute. However, this can only be done if not
passing arguments to the program.

Python3 subprocess module: Passing an empty variable as a flag, is it possible?

I am trying to use subprocess.call() to execute a command-line program in python3. I can get it to work fine, the following example executes with no problems:
subprocess.call(['add_phenotype.py', '-t', threads, '-s'])
However, I want to parse a file, and then based on what I find, run the command with different flags. I can't figure out how to do this.
For example:
if zeroed_out_file:
args = '-z'
else:
args = ''
subprocess.call(['add_phenotype.py', '-t', threads, '-s', args])
fails if zeroed_out_file is FALSE. The add_phenotype.py script exits immediately claiming that it doesn't recognize the arguments.
The first argument takes a list; just build that list dynamically:
args = ['add_phenotype.py', '-t', threads, '-s']
if zeroed_out_file:
args.append('-z')
subprocess.call(args)
Appending additional command line switches is just a question of appending more values to args.

Categories