0

I am trying to execute a shell command kubectl get ns | grep -E '(^|\s)namespace-test($|\s)' but I am getting empty even if there are errors or not.

Reason I am getting empty for both error and non error cases is it executes the command in two times (commands left and right to |), But what I need is to get the actual output as a return value, say 0 if there is an output, or 1 if there is no output

This is what I am trying:

get_ns_p1 = subprocess.Popen(['kubectl', 'get', 'ns'], stdout=subprocess.PIPE)
get_ns_p2 = subprocess.Popen(["grep", "-E", "\'(^|\s)"+NAMESPACE+"($|\s)\'"], stdin=get_ns_p1.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)


get_ns_p1.stdout.close() # Allow proc1 to receive a SIGPIPE if proc2 exits.
out_ns, err = get_ns_p2.communicate()

print(out_ns)

can someone help me?

or if you have any approach for this, this is what I want to do...

I want to execute a shell command which has a pipe and get the output, if there is an output, it should return some value, if the output is empty it should gives a different value, if there is an error it should gives another different output

How can I achieve this?

Jananath Banuka
  • 493
  • 3
  • 11
  • 22
  • split command by pipe like this: `return [command for command in cmd.partition('|') if command != '|' if command != '']` then create `for` loop and call first element form list with `subprocess.Popen`, the next elements should be passed with the result of the previous command in `stdin` – karolch Nov 29 '19 at 12:33
  • Would you help me out with an example please? :) I am new to python – Jananath Banuka Nov 29 '19 at 12:40
  • Take a look at answer. If it works, mark it as the correct solution. Regards – karolch Nov 29 '19 at 13:00

1 Answers1

0

Python 2.7 - 3.x

Tested on CentOs

First of all, you have to split your command by pipe. Like this: [command for command in cmd.partition('|') if command != '|' if command != '']

After that, you have to start your subprocess.Popen command. The first time, execute the first item from the list, after that you can execute next elements, but you have to pass to stdin result of previous execution. This will allow you to execute your pipe command.

However, be careful with shell=True. More information here.

Example code:

import logging
import subprocess  # nosec

logging.basicConfig(filename='log.log',
                    filemode='a',
                    format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
                    datefmt='%H:%M:%S',
                    level=logging.INFO)

log = logging.getLogger(__name__)


def execute_and_create_output_from_cmd(cmd_parts):
    """
    Functions executes cmd and adds parsed lines to <List> result.
    :return: <List>
    """
    try:
        index = 0
        process = {}
        for cmd_part in cmd_parts:
            cmd_part = cmd_part.strip()
            if index == 0:
                process[index] = subprocess.Popen(cmd_part, shell=True,  # nosec
                                                  stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            else:
                process[index] = subprocess.Popen(cmd_part, shell=True,  # nosec
                                                  stdin=process[index - 1].stdout, stdout=subprocess.PIPE,
                                                  stderr=subprocess.PIPE)
            index += 1
        (output, err) = process[index - 1].communicate()
        exit_code = process[0].wait()

        if exit_code != 0:
            log.warning('Output: %s', output)
            log.error('Error: %s', err)
            log.error('Exit code: %s', exit_code)
        else:
            print(output)  # do whatever you want with your output
    except OSError as os_error:
        log.error('Could not execute command: %s', os_error)


def split_cmd(cmd):
    """ Split cmd command. Check if command contains '|'. '||' allowed. """
    return [command for command in cmd.partition('|') if command != '|' if command != '']


if __name__ == '__main__':
    cmd = split_cmd('ls -al | grep ibm')
    execute_and_create_output_from_cmd(cmd)

I have added logging. It is not necessary.

Output:

[kchojnowski@zabbix4-worker1 ~]$ python test.py
drwxrwxr-x  2 kchojnowski kchojnowski    50 Jul 24 15:33 ibm_mq
karolch
  • 184
  • 4
  • 19