Exceptions and exit status codes are two very different things. Exceptions are at the scope of the application; exit status codes are at the scope of the operating system.
When an application calls another one, basically, the only standard way for it to determine that the callee finished successfully is the exit status code. 0
means success. Anything else means failure. The fact that there is no standard for which code is which means that determining the source of the failure often requires to do an additional step of browsing the documentation, when available. Given the vast diversity of issues, creating such standard would be both practically and theoretically impossible: even if you can standardize some errors, such as "file not found", an exit code, that is a simple number, won't be detailed enough: in a case of a file not being found, which file exactly was expected?
This flaw is exactly the same as the one which pushed to abandon error codes within a program and use exceptions instead.
Exceptions:
Are often explicit, as they contain the type, the summary and additional data. The type FileNotFoundException
coupled with the path of the expected file and the stack trace helps identifying very precisely the problem, both as a user of a program and as a programmer—if it's the fault of the program for being unable to find the file or not being able to fallback to another option.
Can be caught within the application itself.
When it comes to inter-process communication, web services, for example, make it possible to emulate at least the first benefit of the exceptions, by providing JSON/XML representation of an error, rather than just a error code.