This article describes how to encapsulate shell commands in Python. An example shows how to encapsulate various common shell commands into a class for calling. it is of great practical value, for more information about how to encapsulate shell commands in Python, see the following example. Share it with you for your reference. The specific implementation method is as follows:
#-*-Coding: UTF-8-*-import osimport subprocessimport signalimport pwdimport sysclass MockLogger (object): ''' simulate the log class. Facilitate unit testing. '''Def _ init _ (self): self.info = self. error = self. critical = self. debug def debug (self, msg): print "LOGGER:" + msgclass Shell (object): ''' to package the Shell script. The execution results are stored in Shell. ret_code, Shell. ret_info, and Shell. err_info. run () is a normal call and will wait for the shell command to return. Run_background () is an asynchronous call and will return immediately. if you do not wait for the shell command to complete the Asynchronous call, you can use get_status () to query the status or use wait () to enter the blocking status, wait until the shell execution is complete. After you use kill () to forcibly stop the script during asynchronous calling, you still need to use wait () to wait for the script to exit. TODO does not verify that Shell commands contain ultra-large output results. '''Def _ init _ (self, cmd): self. cmd = cmd # cmd includes commands and parameters self. ret_code = None self. ret_info = None self. err_info = None # replace it with the specific logger self. logger = MockLogger () def run_background (self): ''' the shell command is executed in non-blocking mode (the default Popen mode ). '''Self. logger. debug ("run % s" % self. cmd) # Popen will throw an OSError exception when the command to be executed does not exist, but after shell = True, # shell will handle the error that the command does not exist, so there is no OSError exception, therefore, you do not need to process self. _ process = subprocess. popen (self. cmd, shell = True, stdout = subprocess. PIPE, stderr = subprocess. PIPE) # Non-blocking def run (self): ''' execute shell commands in blocking mode. '''Self. run_background () self. wait () def run_cmd (self, cmd): ''' run a command directly. It is convenient for one instance to execute multiple commands repeatedly. '''Self. cmd = cmd self. run () def wait (self): ''' wait until shell execution is complete. '''Self. logger. debug ("waiting % s" % self. cmd) self. ret_info, self. err_info = self. _ process. communicate () # Blocking # returncode: A negative value-N indicates that the child was # terminated by signal N self. ret_code = self. _ process. returncode self. logger. debug ("waiting % s done. return code is % d "% (self. cmd, self. ret_code) def get_status (self): ''' get the script RUNNING status (RUNNING | FINISHED) ''' retcode = self. _ process. p Oll () if retcode = None: status = "RUNNING" else: status = "FINISHED" self. logger. debug ("% s status is % s" % (self. cmd, status) return status # The subprocess of Python2.4 does not have send_signal, terminate, and kill # So here we need to copy one, 2.7 can directly use self. _ process kill () def send_signal (self, sig): self. logger. debug ("send signal % s to % s" % (sig, self. cmd) OS. kill (self. _ process. pid, sig) def terminate (self): self. send_signal (signal. SIGT ERM) def kill (self): self. send_signal (signal. SIGKILL) def print_result (self): print "return code:", self. ret_code print "return info:", self. ret_info print "error info:", self. err_infoclass RemoteShell (Shell): ''' remote command execution (ssh mode ). XXX commands with special characters may cause invalid calls, such as double quotation marks. $ NOTE: If cmd contains double quotation marks, you can use RemoteShell2 ''' def _ init _ (self, cmd, ip): ssh = ("ssh-o PreferredAuthentications = publickey-o" "StrictHostKeyChecking = no-o ConnectTimeout = 10") # you do not have to check the IP address validity or trust relationship, shell reports the following error: cmd = '% s "% s"' % (ssh, ip, cmd) Shell. _ init _ (self, cmd) class RemoteShell2 (RemoteShell): ''' is the same as RemoteShell, but the quotation marks are changed. '''Def _ init _ (self, cmd, ip): RemoteShell. _ init _ (self, cmd, ip) self. cmd = "% s '% s'" % (ssh, ip, cmd) class SuShell (Shell): ''' switch the user to execute the command (su mode ). XXX is only applicable to switching from root to other users. Because other users need to enter the password after switching, the program will be suspended. XXX commands with special characters may cause invalid calls, such as double quotation marks. $ NOTE: If cmd contains double quotation marks, you can use SuShell2 ''' def _ init _ (self, cmd, user): if OS. getuid ()! = 0: # raise Exception ('sushell must be called by root user! ') Cmd = 'Su-% s-c "% s"' % (user, cmd) Shell. _ init _ (self, cmd) class SuShell2 (SuShell): ''' is the same as SuShell, but the quotation marks are changed. '''Def _ init _ (self, cmd, user): SuShell. _ init _ (self, cmd, user) self. cmd = "su-% s-c '% s'" % (user, cmd) class SuShellDeprecated (Shell): ''' switch the user to execute the command (setuid mode ). The executed function is run2, instead of running XXX in the "not clean" mode: only the user and group are switched, and the environment variable information remains unchanged. XXX cannot obtain the ret_code, ret_info, and err_info of the command. XXX is only applicable to switching from root to other users. '''Def _ init _ (self, cmd, user): self. user = user Shell. _ init _ (self, cmd) def run2 (self): if OS. getuid ()! = 0: # raise Exception ('sushell2 must be called by root user! ') Child_pid = OS. fork () if child_pid = 0: # uid for sub-processes, gid = pwd. getpwnam (self. user) [2: 4] OS. setgid (gid) # you must first set the OS group. setuid (uid) self. run () sys. exit (0) # The sub-process exits to prevent other code from being executed. else: # the parent process waits for the sub-process to exit the OS. waitpid (child_pid, 0) if _ name _ = "_ main _": '''test code''' #1. test normal sa = Shell ('who ') sa. run () sa. print_result () #2. test stderr sb = Shell ('ls/export/dir_should_not_exists ') sb. run () sb. print_result () #3. test background SC = Shell ('sleep 1') SC. run_background () print 'Hello from parent process' print "return code:", SC. ret_code print "status:", SC. get_status () SC. wait () SC. print_result () #4. test kill import time sd = Shell ('sleep 2') sd. run_background () time. sleep (1) sd. kill () sd. wait () # NOTE, still need to wait sd. print_result () #5. test multiple command and uncompleted command output se = Shell ('pwd; sleep 1; pwd; pwd') se. run_background () time. sleep (1) se. kill () se. wait () # NOTE, still need to wait se. print_result () #6. test wrong command sf = Shell ('aaaaa') sf. run () sf. print_result () #7. test instance reuse to run other command sf. cmd = 'echo aaaaa' sf. run () sf. print_result () sg = RemoteShell ('pwd', '2017. 0.0.1 ') sg. run () sg. print_result () # unreachable ip sg2 = RemoteShell ('pwd', '17. 0.0.1 ') sg2.run () sg2.print _ result () # invalid ip sg3 = RemoteShell ('pwd', '2017. 0.0.1 ') sg3.run () sg3.print _ result () # ip without trust relation sg3 = RemoteShell ('pwd', '10. 145.132.247 ') sg3.run () sg3.print _ result () sh = SuShell ('pwd', 'ossuser') sh. run () sh. print_result () # wrong user si = SuShell ('pwd', 'ossuser123 ') si. run () si. print_result () # user need password si = SuShell ('pwd', 'root') si. run () si. print_result ()
I hope this article will help you with Python programming.