In a sense, a shell can only return an exit code. But it's better to think of that as an error handling mechanism rather than the return value, much like in C. In C, it's idiomatic for functions to return values with "out params" (i.e. a dynamically allocated a string).
Just like you can write C code that composes, you can also write shell code that composes. And in many ways it composes better than code in other languages.
Pipelines Support Vectorized, Point-Free, and Imperative Style
http://www.oilshell.org/blog/2017/01/15.html
In a sense, a shell can only return an exit code. But it's better to think of that as an error handling mechanism rather than the return value, much like in C. In C, it's idiomatic for functions to return values with "out params" (i.e. a dynamically allocated a string).
Just like you can write C code that composes, you can also write shell code that composes. And in many ways it composes better than code in other languages.