Monads are just one design pattern for handling state, and not the only way. It's no different than having an OOP using dependency injection everywhere - it's a design decision that you use only when it makes architectural sense.
A shell is not more imperative than a processor - both are Turing machines, a completely functional mathematical object. Seeing them as imperative is a semantic interpretation of the people watching it, not an inherent property.
Functional languages have either converged on either just allowing mutable values or relying on Monads as the ways of handling state. I'm not aware of a third solution.
A shell is not more imperative than a processor - both are Turing machines, a completely functional mathematical object. Seeing them as imperative is a semantic interpretation of the people watching it, not an inherent property.