Sanity check: As far as I understand, the shell is the interface through which the user can interact with the OS, i.e.: run other processes.
Yes, but a "shell" is specifically a user interface, not a programming interface. Other programs are not required to interact with it – they can directly use the same system calls to create new processes.
So the command-line shell is on the same level as other programs, e.g. service managers, or graphical user interfaces (graphical shells).
Although the shell (e.g. Bash) is just another process.
Yes. On Unix-like systems it is a completely normal, unprivileged process.
Is there a way to run a process that will not be a child of a shell process?
From a user's perspective: yes, there are several ways.
Most shells have an
exec keyword which causes the new program to replace the shell (retaining the same PID and parentship), which is probably not what you meant, but technically what you asked for.
Graphical desktop sessions will often start without invoking bash or any other shell, and this automatically applies to apps launched through the graphical menus. The app's parent will be whatever process was responsible for showing the menu (e.g. the window manager or the panel).
The currently popular systemd init system does not use a shell at all when starting services, so you can define a .service and start it – the service's parent will be init itself. It also has a feature allowing temporary services to be created on-the-fly using
systemd-run, with the same results.
From a programmer's perspective, just use the
execve() system calls to launch a new process. (There are OS-specific details, e.g. fork() might in fact be a wrapper for a different call, but it still works the same way.)
Indeed, even if the program wanted to invoke a shell, it would do so by creating a new child process and running /bin/sh using the same fork+exec. There is no special system call to run a shell. (The programmer could use e.g. system() when writing in C, or os.system() in Python, but those are still just convenience wrappers around fork/exec.)
Environment variables: In bash, there are several scripts that run when you spawn a shell, e.g. .bashrc, .bash_profile, etc. (depends on the type of shell - interactive vs non-interactive, login vs non-login). These scripts define the environment variables. If there's a way to run a process regardless to any shell, where do environment variables come from?
Well, sometimes they don't. (It's a real practical problem when trying to make graphical apps pick up environment customizations, depending on how that particular graphical environment starts.)
Overall, though, environment variables are not unique to CLI shells. Each process, no matter how it was started (including even the init process), receives an array of strings containing its command line – and an array of strings containing its environment variables. When launching a child process, it can either specify a different environment or allow a copy of its own environment to be inherited.
So when you log in, your shell already receives a few initial environment variables from its parent. Those startup scripts (bashrc, etc.) are just a convenient place for a user to customize the environment variables that the shell's child processes will then inherit.
Many parts of this answer also fully apply to Windows – although its graphical interface is a bit more complex, the CLI shells (cmd.exe and PowerShell) are still ordinary programs that aren't used at all in normal operation. The only major difference is that Windows has a single "CreateProcess" call instead of the Unix-style separate "fork + exec" calls.