Skip to main content

Continuous shell process

Project description

Install

pip install shell_proc

Run

Run a series of commands with results.

from shell_proc import Shell

with Shell() as sh:
    sh('cd ..')
    if sh.is_windows():
        cmd = sh('dir')
    else:
        cmd = sh('ls')

    # cmd (Command) Attributes: cmd, exit_code, stdout, stderr
    print(cmd.stdout)

Run a series of terminal commands.

import sys
from shell_proc import Shell

with Shell(stdout=sys.stdout, stderr=sys.stderr) as sh:
    sh.run('mkdir storage')
    sh('cd storage')  # Same as sh.run()
    sh('echo Hello World! > hello.txt')

    if sh.is_windows():
        sh('python -m venv ./winvenv')
        sh('call ./winvenv/Scripts/activate.bat')
    else:
        pwd = sh('pwd')
        sh('cd ~')
        sh('python3 -m venv ./lxvenv')
        sh('source ./lxvenv/bin/activate')
        sh('cd {}'.format(pwd.stdout))
    sh('pip install requests')
    sh('pip list')

table = '|{:_<20}|{:_<20}|{:_<20}|{:_<50}|'
print(table.format('', '', '', '').replace('|', '_'))
print(table.format("Exit Code", "Has Error", "Has Ouput", "Command").replace('_', ' '))
print(table.format('', '', '', ''))
for cmd in sh.history:
    print(table.format(cmd.exit_code, cmd.has_error(), cmd.has_output(), cmd.cmd).replace('_', ' '))
print(table.format('', '', '', '').replace('|', '_'))

Run without blocking every command

import sys
import time
from shell_proc import Shell

with Shell(stdout=sys.stdout, stderr=sys.stderr, blocking=False, wait_on_exit=True) as sh:
    sh.run('mkdir storage')
    sh('cd storage')  # Same as sh.run()
    sh('echo Hello World! > hello.txt')

    if sh.is_windows():
        sh('python -m venv ./winvenv')
        sh('call ./winvenv/Scripts/activate.bat')
    else:
        pwd = sh('pwd')
        sh('cd ~')
        sh('python3 -m venv ./lxvenv')
        sh('source ./lxvenv/bin/activate')
        sh('cd {}'.format(pwd.stdout))
    sh('pip install requests')
    sh('pip list')
    print('---------- At exit (shows non-blocking until exit) ----------')

time.sleep(1)
print('1 Second has passed', 'Running:', sh.current_command)
time.sleep(1)
print('2 Seconds have passed', 'Running:', sh.current_command)
time.sleep(1)
print('3 Seconds have passed', 'Running:', sh.current_command)

sh.wait()  # Wait for all commands to finish

Manually call commands and check results.

import io
import sys
from shell_proc import Shell

# Initialize and run tasks
sh = Shell('mkdir storage',
           'cd storage',
           'echo Hello World! > hello.txt',
           stderr=io.StringIO())

# Manually run tasks
if sh.is_windows():
    sh('python -m venv ./winvenv')
    sh('call ./winvenv/Scripts/activate.bat')
else:
    pwd = sh('pwd')
    sh('cd ~')
    sh('python3 -m venv ./lxvenv')
    sh('source ./lxvenv/bin/activate')
    sh('cd {}'.format(pwd.stdout))

# Not exactly success. If True no output was printed to stderr. Stderr could also be warning like need to update pip
results = sh.run('pip install requests')
print("***** Successful install: ", results.exit_code == 0)
if results.exit_code != 0:
    sh.stderr.seek(0)  # Move to start of io.StringIO()
    err = sh.stderr.read()  # All text collected into stderr from subprocess stderr
    print(err, file=sys.stderr)
    # sh.print_stderr()  # Also available

sh.stdout = io.StringIO()  # Start saving output for new tasks
results = sh('pip list')
print('***** Output Printed\n', results.stdout)

sh('pip -V')
print('pip -V =>', sh.last_command.stdout)

print('All collected stdout')
sh.stdout.seek(0)  # Move to start of io.StringIO()
print(sh.stdout.read(), end='', flush=True)  # Print all read data

# Should close when finished to stop threads from reading stdout and stderr subprocess.PIPE
# (will close automatically eventually)
sh.close()

io.StringIO() Help

Below are several functions to read data from stdout and io.StringIO()

def read_io(fp):
    """Return all of the human readable text from the io object."""
    try:
        if fp.seekable():
            fp.seek(0)
        out = fp.read()
        if not isinstance(out, str):
            out = out.decode('utf-8')
        return out
    except:
        return ''

def clear_io(fp):
    """Try to clear the stdout"""
    text = read_io(fp)
    try:
        fp.truncate(0)
    except:
        pass
    return text

def print_io(fp, end='\n', file=None, flush=True):
    """Print and clear the collected io."""
    if file is None:
        file = sys.stdout
    print(clear_io(fp), file=file, flush=True)

Run Python

Added support to call python in a subprocess

from shell_proc import Shell

with Shell(python_call='python3') as sh:
    sh.python('-c',
              'import os',
              'print("My PID:", os.getpid())')

Run Parallel

Added support to run parallel subprocesses

import sys
import time
from shell_proc import Shell, python_args

with Shell(stdout=sys.stdout, stderr=sys.stderr) as sh:
    p = sh.parallel(*(python_args('-c',
                'import os',
                'import time',
                "print('My ID:', {id}, 'My PID:', os.getpid(), time.time())".format(id=i)) for i in range(10)))
    sh.wait()  # or p.wait()
    print('finished parallel')
    time.sleep(1)

    tasks = []
    for i in range(10):
        if i == 3:
            t = python_args('-c',
                'import os',
                'import time',
                'time.sleep(1)',
                "print('My ID:', {id}, 'My PID:', os.getpid(), time.time())".format(id=i))
        else:
            t = python_args('-c',
                'import os',
                'import time',
                "print('My ID:', {id}, 'My PID:', os.getpid(), time.time())".format(id=i))
        tasks.append(t)
    p = sh.parallel(*tasks)
    p.wait()
    print('finished parallel')
    time.sleep(1)

    with sh.parallel() as p:
        for i in range(10):
            if i == 3:
                p.python('-c',
                         'import os',
                         'import time',
                         'time.sleep(1)',
                         "print('My ID:', {id}, 'My PID:', os.getpid(), time.time())".format(id=i))
            else:
                p.python('-c',
                         'import os',
                         'import time',
                         "print('My ID:', {id}, 'My PID:', os.getpid(), time.time())".format(id=i))
        # p.wait() on exit context
    print('finished parallel')

Use Pipe

The pipe operator can be used with Command objects to take a completed command stdout and submit the text into a new commands stdin.

import sys
from shell_proc import Shell, ShellExit, shell_args

with Shell(stdout=sys.stdout, stderr=sys.stderr) as sh:
    # One step
    results = sh('dir') | 'find "run"'  # Hard to tell where find output starts

    # Two Steps
    cmd = sh('dir')
    results = cmd | 'find "run"'

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

shell_proc-1.2.2.tar.gz (14.7 kB view details)

Uploaded Source

Built Distribution

shell_proc-1.2.2-py3-none-any.whl (32.5 kB view details)

Uploaded Python 3

File details

Details for the file shell_proc-1.2.2.tar.gz.

File metadata

  • Download URL: shell_proc-1.2.2.tar.gz
  • Upload date:
  • Size: 14.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.3

File hashes

Hashes for shell_proc-1.2.2.tar.gz
Algorithm Hash digest
SHA256 517d58731e61ae073e9028658b04bd46648a2b097af8c69b89e3244289d47226
MD5 15f9fb350c869fcab2cc7fec41a6d954
BLAKE2b-256 d3b01325f15f89a48a25df84bcff5f0d2809c09d609dd6b18e30c6732d919ab4

See more details on using hashes here.

File details

Details for the file shell_proc-1.2.2-py3-none-any.whl.

File metadata

  • Download URL: shell_proc-1.2.2-py3-none-any.whl
  • Upload date:
  • Size: 32.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.3

File hashes

Hashes for shell_proc-1.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 31977dec7adcba873c3d0ba13788384782d815f122fc20898c2ea8156567bb3d
MD5 cd760298c01e3d80d61541a081f4b5b2
BLAKE2b-256 68594b7810981dda9d4df18b537969c4ac800f404a3f139ba5b490babc0ae0d7

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page