0

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?

wjandrea
  • 28,235
  • 9
  • 60
  • 81
Matty
  • 175
  • 11
  • 2
    What's the use of `| >> log`? – oguz ismail Mar 12 '20 at 11:53
  • 2
    In your file `c`, when you do `source ./a | >> log`, the statement `source ./a` doesn't output anything on stdout, so it makes sense that you get nothing in `log`. – gniourf_gniourf Mar 12 '20 at 11:53
  • This is a simplification of a larger script, where each line outputs to a log file. Whether or not there will be any output from each line is not known. I know there are different ways of solving logging, but I would like to know why this solution does not work. – Matty Mar 12 '20 at 11:58
  • @oguzismail Thank you very much! That would explain it, that comment is worthy as an answer I think. – Matty Mar 12 '20 at 12:59
  • 5
    @oguzismail That's too strong. `d` *can* be executed in the current evironment, if the `lastpipe` option is in effect. But by default, *all* commands in a pipe are executed in a subshell. (You may be thinking of `ksh`.) – chepner Mar 12 '20 at 13:30

2 Answers2

6

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
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
1

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.

wjandrea
  • 28,235
  • 9
  • 60
  • 81