Shells a process with the given shell command.

        `command`
            Shell command to spawn.
        `input_data`
            String to pipe to process as input.
        `background`
            Set to ``True`` to fork process into background.
            NOTE: This exits immediately with no result returned.
        `exitcode`
            Set to ``True`` to also return process exit status code.

        if `exitcode` is ``False``, then this returns output string from
        process or ``None`` if it failed.

        otherwise, this returns a tuple with output string from process or
        ``None`` if it failed and the exit status code.

            Example::
                (``None``, 1) <-- failed
                ('Some data', 0) <-- success

def shell_process(command, input_data=None, background=False, exitcode=False):
    """ Shells a process with the given shell command.

        `command`
            Shell command to spawn.
        `input_data`
            String to pipe to process as input.
        `background`
            Set to ``True`` to fork process into background.
            NOTE: This exits immediately with no result returned.
        `exitcode`
            Set to ``True`` to also return process exit status code.

        if `exitcode` is ``False``, then this returns output string from
        process or ``None`` if it failed.

        otherwise, this returns a tuple with output string from process or
        ``None`` if it failed and the exit status code.

            Example::
                (``None``, 1) <-- failed
                ('Some data', 0) <-- success
        """

    data = None

    try:
        # kick off the process
        kwargs = {
            'shell': isinstance(command, basestring),
            'stdout': subprocess.PIPE,
            'stderr': subprocess.PIPE
        }
        if not input_data is None:
            kwargs['stdin'] = subprocess.PIPE
        proc = subprocess.Popen(command, **kwargs)

        # background exits without checking anything
        if not background:
            output, _ = proc.communicate(input_data)
            retcode = proc.returncode

            if retcode == 0:
                data = str(output).rstrip()
        else:
            retcode = None

            if input_data:
                raise TypeError(u'Backgrounded does not support input data.')

    except OSError as exc:
        retcode = -exc.errno

    if exitcode:
        return data, retcode

    else:
        return data