Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

problem with pipe and background process

22 views
Skip to first unread message

Lorenz

unread,
Jun 24, 2015, 6:11:52 AM6/24/15
to
Hi all,

I've a problem with the following bash script

(
printf "hello\n"
printf "world\n"
) |
if [ -z "$1" ]
then
email -V -s "test" m...@here.com >>log.txt 2>&1 &
else
cat
fi

Since i've added the conditional for debug purposes I'm ending up with
an empty message body.

Only if I remove the final "&" in the email line, I get the correct
result.


Can anyone please explain what's happening here?
--

Lorenz

David W. Hodgins

unread,
Jun 24, 2015, 10:08:56 AM6/24/15
to
That can't be the entire script as nothing is writing to log.txt.

The difference between having the final & and not having it, is that
with it, the command runs in a subshell.

Regards, Dave Hodgins

--
Change nomail.afraid.org to ody.ca to reply by email.
(nomail.afraid.org has been set up specifically for
use in usenet. Feel free to use it yourself.)

Janis Papanagnou

unread,
Jun 24, 2015, 10:11:46 AM6/24/15
to
My guess is that since the process is in the background it has no stdin.
Similar to invoking any standalone program in the background, where the
terminal (not the background process) then gets all the input.

Janis

David W. Hodgins

unread,
Jun 24, 2015, 10:19:30 AM6/24/15
to
On Wed, 24 Jun 2015 10:11:43 -0400, Janis Papanagnou <janis_pa...@hotmail.com> wrote:

> My guess is that since the process is in the background it has no stdin.
> Similar to invoking any standalone program in the background, where the
> terminal (not the background process) then gets all the input.

Ah. Yes. In my earlier reply I missed the | while skimming the script.

Barry Margolin

unread,
Jun 24, 2015, 10:40:11 AM6/24/15
to
In article <mmedqv$hsu$1...@news.m-online.net>,
What does that mean? The terminal is a possible *source* of input, not
the destination.

Background processes inherit stdin the same as foreground processes, so
the email process should get its stdin from the pipe. For instance:

echo hello | { sleep 5; cat; echo done; } &

The shell prompt comes back immediately, and 5 seconds later it prints
"hello" followed by "done".

The problem is related to the combination of "if" and backgrounding.
This works:

echo hello | if [ -z "$1" ]; then { sleep 5; cat; echo done; } ; fi

but this doesn't:

echo hello | if [ -z "$1" ]; then { sleep 5; cat; echo done; } & fi

After 5 seconds it prints "done", but not "hello".

If I change "cat" to "wc -l", it prints 1 in the non-if and foreground
versions, 0 in the if+background version.

--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***

Lorenz

unread,
Jun 24, 2015, 10:55:15 AM6/24/15
to
Barry Margolin wrote:
>In article <mmedqv$hsu$1...@news.m-online.net>,
> Janis Papanagnou <janis_pa...@hotmail.com> wrote:
>> On 24.06.2015 12:13, Lorenz wrote:
>> > [...]
>The problem is related to the combination of "if" and backgrounding.
>This works:
>echo hello | if [ -z "$1" ]; then { sleep 5; cat; echo done; } ; fi
>
>but this doesn't:
>
>echo hello | if [ -z "$1" ]; then { sleep 5; cat; echo done; } & fi
>
>After 5 seconds it prints "done", but not "hello".
>
>If I change "cat" to "wc -l", it prints 1 in the non-if and foreground
>versions, 0 in the if+background version.

Yes, that's the point I wanted to make (not explicitly enough as it
seems 8-) in my original post.


nice stripped-down reproduction receipt by the way 8-)
--

Lorenz

Janis Papanagnou

unread,
Jun 24, 2015, 11:57:03 AM6/24/15
to
What I mean was; if you invoke some_process & then stdin is not split
and a second instance interited to some_process but rather the actual
process (the one where some_proecss was started from) keeps stdin and
some_process doesn't get it.

>
> Background processes inherit stdin the same as foreground processes, so
> the email process should get its stdin from the pipe. For instance:
>
> echo hello | { sleep 5; cat; echo done; } &
>
> The shell prompt comes back immediately, and 5 seconds later it prints
> "hello" followed by "done".

Of course. The echo is passed, no one reads it, so it's finally printed.

>
> The problem is related to the combination of "if" and backgrounding.
> This works:
>
> echo hello | if [ -z "$1" ]; then { sleep 5; cat; echo done; } ; fi
>
> but this doesn't:
>
> echo hello | if [ -z "$1" ]; then { sleep 5; cat; echo done; } & fi
>
> After 5 seconds it prints "done", but not "hello".

Hmm.. I see. - In ksh and in zsh it's printing "hello" and "done".

In bash that must have something to do with the commands after the pipe
being executed in a subprocess; this variant works in bash:

if [ -z "$1" ]; then { sleep 5; cat; echo done; } & fi < <(echo hello)


Janis

Stephane Chazelas

unread,
Jun 24, 2015, 3:20:09 PM6/24/15
to
2015-06-24 10:13:59 +0000, Lorenz:
[...]

Most shells redirect the stdin of they asynchronous jobs to
/dev/null:

~$ sh -c 'readlink /proc/self/fd/0 &'
/dev/null

You can work around that by doing:

(email ... <&3 3<&- &) 3<&0

Now please note that most shells (only exception I know is the
Bourne shell) wait for all the components of their pipeline.

In:

(cmd1) | (cmd2 &)

The second part will return immediately, but cmd1 will only
return when it has finished. In the case of your printf, it will
return instantly as it's writing less than the size of a pipe
buffer. But if you write more than 64k, those printf may block
until that *background* job reads enough from the pipe to clear
enough space to fit all your output.

--
Stephane

Lorenz

unread,
Jun 29, 2015, 4:28:24 AM6/29/15
to
Thanks guys for looking into this.

For confirming the effect, for the explanations and for the possible
solutions.
--

Lorenz
0 new messages