Execute a command in a subshell. Parameters ---------- cmd : str A command to be executed in the system shell. Returns ------- int : child's exitstatus
(self, cmd: str)
| 84 | return None |
| 85 | |
| 86 | def system(self, cmd: str) -> int: |
| 87 | """Execute a command in a subshell. |
| 88 | |
| 89 | Parameters |
| 90 | ---------- |
| 91 | cmd : str |
| 92 | A command to be executed in the system shell. |
| 93 | |
| 94 | Returns |
| 95 | ------- |
| 96 | int : child's exitstatus |
| 97 | """ |
| 98 | import pexpect |
| 99 | |
| 100 | # Get likely encoding for the output. |
| 101 | enc = DEFAULT_ENCODING |
| 102 | |
| 103 | # Patterns to match on the output, for pexpect. We read input and |
| 104 | # allow either a short timeout or EOF |
| 105 | patterns = [pexpect.TIMEOUT, pexpect.EOF] |
| 106 | # the index of the EOF pattern in the list. |
| 107 | # even though we know it's 1, this call means we don't have to worry if |
| 108 | # we change the above list, and forget to change this value: |
| 109 | EOF_index = patterns.index(pexpect.EOF) |
| 110 | # The size of the output stored so far in the process output buffer. |
| 111 | # Since pexpect only appends to this buffer, each time we print we |
| 112 | # record how far we've printed, so that next time we only print *new* |
| 113 | # content from the buffer. |
| 114 | out_size = 0 |
| 115 | assert self.sh is not None |
| 116 | try: |
| 117 | # Since we're not really searching the buffer for text patterns, we |
| 118 | # can set pexpect's search window to be tiny and it won't matter. |
| 119 | # We only search for the 'patterns' timeout or EOF, which aren't in |
| 120 | # the text itself. |
| 121 | #child = pexpect.spawn(pcmd, searchwindowsize=1) |
| 122 | if hasattr(pexpect, 'spawnb'): |
| 123 | child = pexpect.spawnb(self.sh, args=['-c', cmd]) # Pexpect-U |
| 124 | else: |
| 125 | child = pexpect.spawn(self.sh, args=['-c', cmd]) # Vanilla Pexpect |
| 126 | flush = sys.stdout.flush |
| 127 | while True: |
| 128 | # res is the index of the pattern that caused the match, so we |
| 129 | # know whether we've finished (if we matched EOF) or not |
| 130 | res_idx = child.expect_list(patterns, self.read_timeout) |
| 131 | print(child.before[out_size:].decode(enc, 'replace'), end='') |
| 132 | flush() |
| 133 | if res_idx==EOF_index: |
| 134 | break |
| 135 | # Update the pointer to what we've already printed |
| 136 | out_size = len(child.before) |
| 137 | except KeyboardInterrupt: |
| 138 | # We need to send ^C to the process. The ascii code for '^C' is 3 |
| 139 | # (the character is known as ETX for 'End of Text', see |
| 140 | # curses.ascii.ETX). |
| 141 | child.sendline(chr(3)) |
| 142 | # Read and print any more output the program might produce on its |
| 143 | # way out. |