MCPcopy Index your code
hub / github.com/python-cmd2/cmd2 / do_shell

Method do_shell

cmd2/cmd2.py:4744–4798  ·  view source on GitHub ↗

Execute a command as if at the OS prompt.

(self, args: argparse.Namespace)

Source from the content-addressed store, hash-verified

4742 # Preserve quotes since we are passing these strings to the shell
4743 @with_argparser(_build_shell_parser, preserve_quotes=True)
4744 def do_shell(self, args: argparse.Namespace) -> None:
4745 """Execute a command as if at the OS prompt."""
4746 import signal
4747 import subprocess
4748
4749 kwargs: dict[str, Any] = {}
4750
4751 # Set OS-specific parameters
4752 if sys.platform.startswith("win"):
4753 # Windows returns STATUS_CONTROL_C_EXIT when application stopped by Ctrl-C
4754 ctrl_c_ret_code = 0xC000013A
4755 else:
4756 # On POSIX, Popen() returns -SIGINT when application stopped by Ctrl-C
4757 ctrl_c_ret_code = signal.SIGINT.value * -1
4758
4759 # On POSIX with shell=True, Popen() defaults to /bin/sh as the shell.
4760 # sh reports an incorrect return code for some applications when Ctrl-C is pressed within that
4761 # application (e.g. less). Since sh received the SIGINT, it sets the return code to reflect being
4762 # closed by SIGINT even though less did not exit upon a Ctrl-C press. In the same situation, other
4763 # shells like bash and zsh report the actual return code of less. Therefore, we will try to run the
4764 # user's preferred shell which most likely will be something other than sh. This also allows the user
4765 # to run builtin commands of their preferred shell.
4766 shell = os.environ.get("SHELL")
4767 if shell:
4768 kwargs["executable"] = shell
4769
4770 # Create a list of arguments to shell
4771 tokens = [args.command, *args.command_args]
4772
4773 # Expand ~ where needed
4774 utils.expand_user_in_tokens(tokens)
4775 expanded_command = " ".join(tokens)
4776
4777 # Prevent KeyboardInterrupts while in the shell process. The shell process will
4778 # still receive the SIGINT since it is in the same process group as us.
4779 with self.sigint_protection:
4780 # For any stream that is a StdSim, we will use a pipe so we can capture its output
4781 proc = subprocess.Popen( # noqa: S602
4782 expanded_command,
4783 stdout=subprocess.PIPE if isinstance(self.stdout, utils.StdSim) else self.stdout, # type: ignore[unreachable]
4784 stderr=subprocess.PIPE if isinstance(sys.stderr, utils.StdSim) else sys.stderr,
4785 shell=True,
4786 **kwargs,
4787 )
4788
4789 proc_reader = utils.ProcReader(proc, self.stdout, sys.stderr)
4790 proc_reader.wait()
4791
4792 # Save the return code of the application for use in a pyscript
4793 self.last_result = proc.returncode
4794
4795 # If the process was stopped by Ctrl-C, then inform the caller by raising a KeyboardInterrupt.
4796 # This is to support things like stop_on_keyboard_interrupt in runcmds_plus_hooks().
4797 if proc.returncode == ctrl_c_ret_code:
4798 self._raise_keyboard_interrupt()
4799
4800 @staticmethod
4801 def _reset_py_display() -> None:

Callers 2

run_editorMethod · 0.95
test_shell_manual_callFunction · 0.80

Calls 3

waitMethod · 0.95
getMethod · 0.45

Tested by 1

test_shell_manual_callFunction · 0.64