Os.System() Execute Command Under Which Linux Shell

os.system() execute command under which linux shell?

os.system() just calls the system() system call ("man 3 system"). On most *nixes this means you get /bin/sh.

Note that export VAR=val is technically not standard syntax (though bash understands it, and I think ksh does too). It will not work on systems where /bin/sh is actually the Bourne shell. On those systems you need to export and set as separate commands. (This will work with bash too.)

How to force os.system() to use bash instead of shell

Both commands are executed in different subshells.

Setting variables in the first system call does not affect the second system call.

You need to put two command in one string (combining them with ;).

>>> import os
>>> os.system('GREPDB="echo 123"; /bin/bash -c "$GREPDB"')
123
0

NOTE You need to use "$GREPDB" instead of '$GREPDBS'. Otherwise it is interpreted literally instead of being expanded.

If you can use subprocess:

>>> import subprocess
>>> subprocess.call('/bin/bash -c "$GREPDB"', shell=True,
... env={'GREPDB': 'echo 123'})
123
0

How do I execute a program or call a system command?

Use the subprocess module in the standard library:

import subprocess
subprocess.run(["ls", "-l"])

The advantage of subprocess.run over os.system is that it is more flexible (you can get the stdout, stderr, the "real" status code, better error handling, etc...).

Even the documentation for os.system recommends using subprocess instead:

The subprocess module provides more powerful facilities for spawning new processes and retrieving their results; using that module is preferable to using this function. See the Replacing Older Functions with the subprocess Module section in the subprocess documentation for some helpful recipes.

On Python 3.4 and earlier, use subprocess.call instead of .run:

subprocess.call(["ls", "-l"])

How would I store the shell command output to a variable in python?

By using module subprocess. It is included in Python's standard library and aims to be the substitute of os.system. (Note that the parameter capture_output of subprocess.run was introduced in Python 3.7)

>>> import subprocess
>>> subprocess.run(['cat', '/etc/hostname'], capture_output=True)
CompletedProcess(args=['cat', '/etc/hostname'], returncode=0, stdout='example.com\n', stderr=b'')
>>> subprocess.run(['cat', '/etc/hostname'], capture_output=True).stdout.decode()
'example.com\n'

In your case, just:

import subprocess

v = subprocess.run(['cat', '/etc/redhat-release'], capture_output=True).stdout.decode()

Update: you can split the shell command easily with shlex.split provided by the standard library.

>>> import shlex
>>> shlex.split('cat /etc/redhat-release')
['cat', '/etc/redhat-release']
>>> subprocess.run(shlex.split('cat /etc/hostname'), capture_output=True).stdout.decode()
'example.com\n'

Update 2: os.popen mentioned by @Matthias

However, is is impossible for this function to separate stdout and stderr.

import os

v = os.popen('cat /etc/redhat-release').read()

How to execute a shell program taking inputs with python?

I'll try and give you some hints to get you started - though bear in mind I do not know any of your tools, i.e. waf or csp-client, but hopefully that will not matter.

I'll number my points so you can refer to the steps easily.


Point 1

If waf is a build system, I wouldn't keep running that every time you want to run your csp-client. Just use waf to rebuild when you have changed your code - that should save time.


Point 2

When you change directory to /home/augustin/workspaceGS/gs-sw-nanosoft-product-interface-application-2.5.1 and then run ./build/csp-client you are effectively running:

/home/augustin/workspaceGS/gs-sw-nanosoft-product-interface-application-2.5.1/build/csp-client -k/dev/ttyUSB1

But that is rather annoying, so I would make a symbolic link to that that from /usr/local/bin so that you can run it just with:

csp-client -k/dev/ttyUSB1

So, I would make that symlink with:

ln -s /home/augustin/workspaceGS/gs-sw-nanosoft-product-interface-application-2.5.1/build/csp-client  /usr/local/bin/csp-client

You MAY need to put sudo at the start of that command. Once you have that, you should be able to just run:

csp-client -k/dev/ttyUSB1

Point 3

Your Python code doesn't work because every os.system() starts a completely new shell, unrelated to the previous line or shell. And the shell that it starts then exits before your next os.system() command.

As a result, the cmp ident command never goes to the csp-client. You really need to send the cmp ident command on the stdin or "standard input" of csp-client. You can do that in Python, it is described here, but it's not all that easy for a beginner.

Instead of that, if you just have aa few limited commands you need to send, such as "take a picture", I would make and test complete bash scripts in the Terminal, till I got them right and then just call those from Python. So, I would make a bash script in your HOME directory called, say csp-snap and put something like this in it:

#/bin/bash

# Extend PATH so we can find "/usr/local/bin/csp-client"
PATH=$PATH:/usr/local/bin

{
# Tell client to take picture
echo "nanoncam snap"
# Exit csp-client
echo exit
} | csp-client -k/dev/ttyUSB1

Now make that executable (only necessary once) with:

chmod +x $HOME/csp-snap

And then you can test it with:

$HOME/csp-snap

If that works, you can copy the script to /usr/local/bin with:

cp $HOME/csp-snap /usr/local/bin

You may need sudo at the start again.

Then you should be able to take photos from anywhere just with:

csp-snap

Then your Python code becomes easy:

os.system('/usr/local/bin/csp-snap')

Unable to call bash script using os.system() on Windows

os.system() will invoke your command the same as windows cmd would, in this case, the windows doesn't know how to execute *.sh files, so it opens it's default dialog so you can pick one program that you know can ran it.

The same will happen if you open windows terminal and try to invoke such file.

If your windows have a bash interpreter try invoking it like this:

os.system("bash Y:\test.sh")

Python: Understanding the behaviour of os.system on linux and freeBSD

"sh" is not same on Linux and FreeBSD. Linux's /bin/sh makes fork() call, but FreeBSD's /bin/sh makes execve() call to execute command, so it doesn't produce new process shown in Linux.

Linux:

sh-4.1$ sh --version
sh --version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

FreeBSD:

man sh
DESCRIPTION
The sh utility is the standard command interpreter for the system. The
current version of sh is close to the IEEE Std 1003.1 (“POSIX.1”)
specification for the shell. It only supports features designated by
POSIX, plus a few Berkeley extensions. This man page is not intended to
be a tutorial nor a complete specification of the shell
HISTORY
A sh command, the Thompson shell, appeared in Version 1 AT&T UNIX. It was
superseded in Version 7 AT&T UNIX by the Bourne shell, which inherited the
name sh.

This version of sh was rewritten in 1989 under the BSD license after the
Bourne shell from AT&T System V Release 4 UNIX.

AUTHORS
This version of sh was originally written by Kenneth Almquist.


Related Topics



Leave a reply



Submit