The bash source command does not work with pipe

1.6k views Asked by At

There are 3 files (a, b and c), all with 777 permissions:

$ ls
a  b  c

The above files have the following contents:

$ cat a
#!/bin/bash
export A=aaa
$ cat b
#!/bin/bash
source ./a
echo $A
$ cat c
#!/bin/bash
source ./a | >> log
echo $A

The only difference between b and c is | >> log:

$ diff b c
2c2
< source ./a
---
> source ./a | >> log

When b is executed it outputs the expected aaa:

$ ./b
aaa

When c is executed it outputs, for me, an unexpected blank row instead of the expected aaa, and the log file that script c created is empty:

$ ./c

$ cat log
$

Clearly, there is something about source and | that I have yet to learn.

Could someone please enlighten me regarding why c does not output aaa?

2

There are 2 answers

0
Charles Duffy On

Use a process substitution instead of a pipeline:

source ./a > >(tee -a log)

That way your source command runs in the original shell.

Alternately, stop creating a pipeline at all:

source ./a >>log
0
wjandrea On

In Bash, the first command in a pipeline will always be executed in a subshell, so any variables that it imports are lost. But a pipeline is not what you want in the first place. With foo | >> file, it redirects the output of foo into a null command, then the output of the null command (which is null) is appended to the file. I'm not sure why Bash allows the second command in the pipeline to be null when there's a redirection.

You want command >> file, i.e.

$ cat c
#!/bin/bash
source ./a >> log
echo $A

Although source ./a doesn't produce any output.