KnowHow

技術的なメモを中心にまとめます。
検索にて調べることができます。

[ライブラリ:python]Linuxでシェルを実行するプログラム

登録日 :2024/09/24 05:18
カテゴリ :Python基礎

pythonにてsubprocessを用いてコマンドやシェルを実行する自作のライブラリ。これをベースに様々なプログラムを作成する。

#!/usr/bin/python3

import subprocess
from subprocess import PIPE
import logging
import time
import datetime
import signal
import os
import sys
import gc

dir_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(dir_path)

from config import settings

"""
created by me.
submit shell command
version 2024.09.23.1
"""

#logging.basicConfig(
#        level=logging.DEBUG)

handler = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter('%(asctime)s:%(name)s:%(levelname)s:%(message)s')
handler.setFormatter(formatter)

logger = logging.getLogger(__name__)
#logger.setLevel(logging.DEBUG)
logger.setLevel(logging.INFO)
logger.addHandler(handler)


logger.debug({'add path': dir_path})


class ShellCommand(object):
    def __init__(self, dt_now, timeout: int, command: str):
        self.stdout = False
        self.stderr = False
        self.returncode = False
        self.command = False
        self._timeout = timeout
        self._command = command
        self._dt_now = dt_now
        self._command_result = False
        self._errlog = False

    def submit_command(self, command):
        self.command = command
        result = subprocess.run(
                self.command,
                shell=True,
                stdout=PIPE,
                stderr=PIPE,
                timeout=self._timeout)
        self.stdout = result.stdout.decode('utf-8')
        self.stderr = result.stderr.decode('utf-8')
        self.returncode = result.returncode

        if result.returncode != 0:
            raise Exception(self.stderr)

    def execute_command(self):
        try:
            self.submit_command(self._command)
            self._command_result = self.stdout
            logger.debug({'shellcommand':'success'})
        except Exception as e:
            self._command_result = self.stderr
            self._errlog = str(e)
            logger.error({
                'time': self._dt_now,
                'status': 'failed',
                'action':'ExceuteShellComand',
                'error': self._errlog,
                'command': self._command})


class ShellCommandSignal(ShellCommand):

    def _signal_handler(self, signum, frame):
        logger.error({
            'statud': "Time out!",
            'action': 'ExecuteShellCommand_signal'})
        raise Exception("catch error timeout")

    def submit_command(self, command):
        self.command = command
        result = subprocess.run(
                self.command,
                shell=True,
                stdout=PIPE,
                stderr=PIPE)
        self.stdout = result.stdout.decode('utf-8')
        self.stderr = result.stderr.decode('utf-8')
        self.returncode = result.returncode

    def execute_command(self):
        signal.signal(signal.SIGALRM, self._signal_handler)
        signal.alarm(self._timeout)

        try:
            self.submit_command(self._command)
            self._command_result = self.stdout
        except Exception as e:
            self._command_result = self.stderr
            self._errlog = str(e)
            logger.error({
                'time': self._dt_now,
                'status': 'failed',
                'action':'ExceuteShellComand_signal',
                'error': self._errlog,
                'command': self._command})


def test_main(_dt_now, _timeout):
    command = 'sleep 3; ls -l'
    shell_command = ShellCommand(_dt_now, _timeout, command)
    shell_command.execute_command()
    logger.info({'test result': shell_command._command_result})


def test_main_signal(_dt_now, _timeout):
    command = 'sleep 3; ls -l'
    shell_command = ShellCommandSignal(_dt_now, _timeout, command)
    shell_command.execute_command()
    logger.info({'test signal result': shell_command._command_result})


if __name__ == '__main__':
    dt_now = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
    timeout = 10

    test_main(dt_now, timeout)

    test_main_signal(dt_now, timeout)