helpThe GNU Bourne-Again SHell - Support: sr #108980, Unexpected behaviour - sourcing...


sr #108980: Unexpected behaviour - sourcing file that contains "exec something-non-existent" closes the shell

Submitted by:  None
Submitted on:  Tue 23 Feb 2016 11:36:36 AM UTC  
Category:  None Priority:  5 - Normal
Severity:  3 - Normal Status:  Postponed
Privacy:  Public Assigned to:  None
Originator Email:  -email is unavailable- Open/Closed:  Open
Operating System:  GNU/Linux

Add a New Comment(Rich Markup)

You are not logged in

Please log in, so followups can be emailed to you.


Wed 24 Feb 2016 05:22:54 PM UTC, comment #1:

The shell is not currently interactive when reading a file argument to the source builtin (interactive == 0), though the shell itself is interactive (interactive_shell == 1). There
are other circumstances when an interactive shell is not
currently interactive (command substitution, executing traps,
running startup files, etc.)

I have not completely decided what to do about this, but I am not inclined right now to change the current behavior.

Chet Ramey <chet>
Project Administrator
Tue 23 Feb 2016 11:36:36 AM UTC, original submission:

Good local!

Some time ago the poster of this question on StackOverflow had found a strange behaviour.

exec "non-existing-file"

non-existing-file command does not exist.
Now run:


It closes the shell, as if it were non-interactive shell or existing command.

(in the `exec.def` code, we see:

if (subshell_environment || (interactive == 0 && no_exit_on_failed_exec == 0))
exit_shell (exit_value);

so, exiting shell would be done
a) on non-interactive shell with `false` "no_exit_on_failed_exec"
b) when `exec` is being run in subshell

For the interactive shell, if the command exist, the shell is replaced by the command invoked).

Now about source:

> When a script is run using `source' it runs within the existing shell,
> any variables created or modified by the script will remain available
> after the script completes.

Will check it:

# Check if the shell is interactive
# based on

echo "First method:"
echo $-
echo "Second method:"
if [[ -z $PS1 ]] # no prompt?
# non-interactive
echo "non-interactive"
# interactive
echo "interactive"

The output:

> First method:
> himBH
> Second method:
> interactive

So, one may convince, `source`, does not fork, and uses current interactive shell.

The situation seems alike when just running `exec non-existent-file`. **So, why does it terminate while using `source`**?

I've compiled `bash-4.2` with `gcc` `-g` flag.

This is ``:

exec "non-existing-file"

I've run it in `gdb` debugger.

chmod +x
gdb bash
./ line 2: exec: non-existing-file: not found

bash: exec: non-existing-file: not found
[Inferior 1 (process 13773) exited with code 0177]

What is 0177? It is not in standard bash exit codes. Though, some web search help us suggest, it is exit code for exec on "File not found".

For trace see attachment.

These are the last commands that being executed before exit:

bash: exec: non-existing-file: не найден
163 exit_value = EX_NOTFOUND; /* As per Posix.2, 3.14.6 */
165 goto failed_exec;
235 FREE (command);
237 if (subshell_environment || (interactive == 0 && no_exit_on_failed_exec == 0))
238 exit_shell (exit_value);
[Inferior 1 (process 4034) exited with code 0177]

Printing the variables:

(gdb) p subshell_environment
$1 = 0
(gdb) p interactive
$2 = 0
(gdb) p no_exit_on_failed_exec
$3 = 0

It turns out, the shell is non-interactive (`interactive=0`) while sourceing the built-in `exec`. This is the reason for such behaviour.
It conradicts the documented behaviour, so, one may say, you've discovered a bug.

Where does `interactive` is set? (using `gdb's "watch" feature`)


Hardware watchpoint 2: interactive

Old value = 1
New value = 0
_evalfile (filename=0xa017a8 "", flags=14) at evalfile.c:226
226 return_catch_flag++;

And it is here: (`evalfile.c`)

223 if (flags & FEVAL_NONINT)
224 interactive = 0;

As one could obtain studying the call stack and stepping through code in gdb, sourcing the file really is performed this way: the whole file contents are combined as one big string in `evalfile.c`, the it is parsed to find separate strings and execute them with `evalstring.c`.

(gdb) p flags
$1 = 14
#define FEVAL_NONINT 0x008
-> 14=1110 & 8=1000 -> 1000 -> interactive = 0 (non-interactive)
The problem is the 4th bit from the right in flags.

#1 0x0000000000485dcf in source_file (filename=0x9fb8c8 "", sflags=0)
at evalfile.c:344
344 rval = _evalfile (filename, flags);

Here is the relevant code of source_file:

339 if (sflags)
340 flags |= FEVAL_NOPUSHARGS;
341 /* POSIX shells exit if non-interactive and file error. */
342 if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
343 flags |= FEVAL_LONGJMP;
344 rval = _evalfile (filename, flags);

sflags=0, interactive_shell=1 here, so

#define FEVAL_BUILTIN 0x002
#define FEVAL_UNWINDPROT 0x004
#define FEVAL_NONINT 0x008

-> flags 1110 =14.

Result: interactive shell converts

At last:
Why doing `source` gives us `i` flag (interactive)?

using `watch` in `gdb` again:
Hardware watchpoint 2: interactive

Old value = 1
New value = 0
_evalfile (filename=0xa014c8 "", flags=14)
at evalfile.c:226
224 interactive = 0;

> First method:
> himBH
> Second method:
> interactive

The bash variables `$PS1` and `$-` and `interactive=0` in internals seem to be not in line with each other.

So, as I understand, it is a bug: `source` executes commands in the current shell, but sets flag `FEVAL_NONINT 0x008` - non-interactive
(bug here):



(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:

Attached Files
file #36438:  trace.txt added by None (2KiB - text/plain)


Depends on the following items: None found

Items that depend on this one: None found


Carbon-Copy List
  • -email is unavailable- added by chet (Posted a comment)
  • -email is unavailable- added by None (Submitted the item)

    Do you think this task is very important?
    If so, you can add your encouragement to it.
    This task has 0 encouragements so far.

    Only logged-in users can vote.




    Follow 2 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2016-02-24 chet StatusNone => Postponed
    2016-02-23 None Attached File- => Added trace.txt, #36438

    Back to the top

    Powered by Savane 3.3