def run(
            self,
            input_=None,
            final_ins=None,
            final_outs=None,
            final_errs=None,
            add_to_history=None,
            add_new_inp_line=None,
            persistent_level=0,
            is_background=False,
            environ={},
            cwd=None
    ):
        """
        This is the entry for running shell commands.

        :param input_: Default to ShIO
        :param final_ins:
        :param final_outs:
        :param final_errs
        :param add_to_history:
        :param add_new_inp_line:
        :param persistent_level:
                    The persistent level dictates how variables from child shell
                    shall be carried over to the parent shell.
                    Possible values are:
                    0 - No persistent at all (shell script is by default in this mode)
                    1 - Full persistent. Parent's variables will be the same as child's
                        (User command from terminal is in this mode).
                    2 - Semi persistent. Any more future children will have starting
                        variables as the current child's ending variables. (__call__
                        interface is by default in this mode).
        :param environ:
        :param cwd:
        :return:
        :rtype: ShBaseThread
        """

        # By default read from the terminal
        if input_ is None:
            input_ = self.stash.io

        # noinspection PyDocstring
        def fn():
            current_worker, _ = self.get_current_worker_and_state()
            is_top = current_worker.is_top_level()

            try:
                if isinstance(input_, ShPipeSequence):
                    self.run_pipe_sequence(
                        input_,
                        final_ins=final_ins,
                        final_outs=final_outs,
                        final_errs=final_errs,
                        environ=environ,
                        cwd=cwd
                    )

                else:
                    if type(input_) is list:
                        lines = input_
                    elif input_ == self.stash.io:
                        lines = self.stash.io.readline_no_block()
                    else:
                        lines = input_.splitlines()

                    for line in lines:
                        # Ignore empty lines
                        if line.strip() == '':
                            continue

                        # Parse and expand the line (note this function returns a generator object)
                        expanded = self.expander.expand(line)
                        # The first member is the history expanded form and number of pipe_sequence
                        newline, n_pipe_sequences = next(expanded)
                        # Only add history entry if:
                        #   1. It is explicitly required
                        #   2. It is the first layer thread directly spawned by the main thread
                        #      and not explicitly required to not add
                        if (add_to_history is None and is_top) or add_to_history:
                            self.history.add(line)  # add non-expanded form to history

                        if is_top:
                            self.history.swap(newline.split(" ")[0] if newline != "" else "")

                        try:
                            # Subsequent members are actual commands
                            for _ in range(n_pipe_sequences):
                                pipe_sequence = next(expanded)
                                if pipe_sequence.in_background:
                                    # For background command, separate worker is created
                                    self.run(
                                        pipe_sequence,
                                        final_ins=final_ins,
                                        final_outs=final_outs,
                                        final_errs=final_errs,
                                        persistent_level=0,
                                        is_background=True,
                                        environ=environ,
                                        cwd=cwd
                                    )
                                else:
                                    self.run_pipe_sequence(
                                        pipe_sequence,
                                        final_ins=final_ins,
                                        final_outs=final_outs,
                                        final_errs=final_errs,
                                        environ=environ,
                                        cwd=cwd
                                    )
                        finally:
                            if is_top:
                                self.history.swap("StaSh.runtime")

            except pp.ParseException as e:
                if self.debug:
                    self.logger.debug('ParseException: %s\n' % repr(e))
                msg = 'syntax error: at char %d: %s\n' % (e.loc, e.pstr)
                self.write_error_message(final_errs, msg)

            except ShEventNotFound as e:
                if self.debug:
                    self.logger.debug('%s\n' % repr(e))
                msg = '%s: event not found\n' % e.args[0]
                self.write_error_message(final_errs, msg)

            except ShBadSubstitution as e:
                if self.debug:
                    self.logger.debug('%s\n' % repr(e))
                msg = '%s\n' % e.args[0]
                self.write_error_message(final_errs, msg)

            except ShInternalError as e:
                if self.debug:
                    self.logger.debug('%s\n' % repr(e))
                msg = '%s\n' % e.args[0]
                self.write_error_message(final_errs, msg)

            except IOError as e:
                if self.debug:
                    self.logger.debug('IOError: %s\n' % repr(e))
                msg = '%s: %s\n' % (e.filename, e.strerror)
                self.write_error_message(final_errs, msg)

            except KeyboardInterrupt as e:
                msg = '^C\nKeyboardInterrupt: %s\n' % e.args[0]
                self.write_error_message(final_errs, msg)

            # This catch all exception handler is to handle errors outside of
            # run_pipe_sequence. The traceback print is mainly for debugging
            # the shell itself as opposed to the running script (handled inside
            # exec_py_file)
            except Exception as e:
                etype, evalue, tb = sys.exc_info()
                if self.debug:
                    self.logger.debug('Exception: %s\n' % repr(e))
                msg = '%s\n' % repr(e)
                self.write_error_message(final_errs, msg)
                if self.py_traceback or self.py_pdb:
                    # traceback.print_exception(etype, evalue, tb, file=(final_errs if final_errs is not None else None))
                    lines = traceback.format_exception(etype, evalue, tb)
                    self.write_error_message(self.stash.text_color("".join(lines), "red"), prefix="")

            finally:
                # Housekeeping for the thread, e.g. remove itself from registry
                current_worker.cleanup()

                # Prompt is now ready for more user input for commands to run,
                # if new input line is explicitly specified or when the worker
                # thread's parent is the runtime itself and new input line is
                # not explicitly suppressed
                if add_new_inp_line or (is_top and add_new_inp_line is not False):
                    self.script_will_end()

                # Saves its state to parent or if persistent is required
                if not current_worker.is_background:
                    current_worker.parent.state.persist_child(current_worker.state, persistent_level=persistent_level)

        # Get the parent thread
        parent_thread = threading.currentThread()

        # UI thread is substituted by runtime
        if not isinstance(parent_thread, ShBaseThread):
            parent_thread = self

        child_thread = self.ShThread(
            self.worker_registry,
            parent_thread,
            input_,
            target=fn,
            is_background=is_background,
            environ=environ,
            cwd=cwd
        )
        child_thread.start()

        return child_thread

        This is the entry for running shell commands.

        :param input_: Default to ShIO
        :param final_ins:
        :param final_outs:
        :param final_errs
        :param add_to_history:
        :param add_new_inp_line:
        :param persistent_level:
                    The persistent level dictates how variables from child shell
                    shall be carried over to the parent shell.
                    Possible values are:
                    0 - No persistent at all (shell script is by default in this mode)
                    1 - Full persistent. Parent's variables will be the same as child's
                        (User command from terminal is in this mode).
                    2 - Semi persistent. Any more future children will have starting
                        variables as the current child's ending variables. (__call__
                        interface is by default in this mode).
        :param environ:
        :param cwd:
        :return:
        :rtype: ShBaseThread
        
system/shruntime.py