Execute shell command and return output

    Args:
        cmd (str): the command itself, i.e. part until the first space
        *args: positional arguments, i.e. other space-separated parts
        rel_path (bool): execute relative to the path (default: `False`)
        raise_on_status(bool): bool, raise exception if command
            exited with non-zero status (default: `True`)
        stderr (file-like): file-like object to collect stderr output,
            None by default

    Returns:
        Tuple[int, str]: status, shell output

def shell(cmd, *args, **kwargs):
    # type: (Union[str, unicode], *Union[str, unicode], **Any) ->Tuple[int, str]
    """ Execute shell command and return output

    Args:
        cmd (str): the command itself, i.e. part until the first space
        *args: positional arguments, i.e. other space-separated parts
        rel_path (bool): execute relative to the path (default: `False`)
        raise_on_status(bool): bool, raise exception if command
            exited with non-zero status (default: `True`)
        stderr (file-like): file-like object to collect stderr output,
            None by default

    Returns:
        Tuple[int, str]: status, shell output

    """
    if kwargs.get('rel_path') and not cmd.startswith("/"):
        cmd = os.path.join(kwargs['rel_path'], cmd)
    status = 0
    try:
        output = subprocess.check_output(
            (cmd,) + args, stderr=kwargs.get('stderr'))
    except subprocess.CalledProcessError as e:
        if kwargs.get('raise_on_status', True):
            raise e
        output = e.output
        status = e.returncode
    except OSError as e:  # command not found
        if kwargs.get('raise_on_status', True):
            raise e
        if 'stderr' in kwargs:
            kwargs['stderr'].write(e.message)
        return -1, ""

    if six.PY3:
        output = output.decode('utf8')
    return status, output