Mac – why error code 1 returned by loading .bash_profile in Mac

.bash-profilebashmac

Whenever I open a bash terminal, the error code 1 is returned:

Last login: Tue Jan 15 16:19:53 on ttys000
spam@moss:~ $ echo $?
1

I found this is caused by last line of code in my .bash_profile:

test -f $HOME/.debug && export profile_bash_profile='.bash_profile' || return 0

If I remove this line, then the error code 0 is returned. I don't understand how this line could cause any problem, because I can source .bash_profile with the error code 0:

spam@moss:~ $ source .bash_profile
spam@moss:~ $ echo $?
0

Update:

Does anyone one know how Mac load ~/.bash_profile? I doubt Mac sources it when a login shell is launched. It seems the return command doesn't run as expected – when I put return 5 as the last line of ~/.bash_profile and launch a login shell, it does not return error code 5 (and I am sure ~/.bash_profile is the last script loaded).

Best Answer

Note that what happens when using return outside a function without having sourced the script (e.g. returning from .bash_profile) is undocumented in man bash.

The difference is in how the return code of a script or function is recorded internally in bash. If you return a value, that value is assigned the return code of the calling code, e.g. the function call you return from, or the source command. As there is no such caller when returning from .bash_profile during shell initialization, that value is simply discarded. What you're accessing as $? is the return code of the preceding statement.

Using Apple's bash-86.1 as reference:

If you source a script, its contents are parsed and executed, until a return statement is encountered. Its return value is recorded separately, and it's the responsibility of the caller (execute_command_internal in bash-3.2/execute_cmd.c) to assign its value to the variable holding the last exit code: last_command_exit_value.

If it's called as a startup script, it is loaded via a call to maybe_execute_file in the run_startup_files function in bash/shell.c. It's not regular command execution: While the contents of the file are executed properly, including the final return, nobody cares about the actual value you're returning. It is simply discarded.

So, what behavior are you seeing here? Essentially the same as if you'd called returnwithout argument: Like return simply returned the return code of the command preceding it, which, in your case, is the failed test.

How to get the desired behavior? Since you can't exit from .bash_profile without quitting the shell, you need to make sure the command immediately preceding it produces the desired return code, in this case:

test -f $HOME/.debug && export profile_bash_profile='.bash_profile' || { true; return; }
Related Question