New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Piping interactive bash to a function stops the process #4929

Closed
JoshCheek opened this Issue Apr 19, 2018 · 7 comments

Comments

Projects
None yet
3 participants
@JoshCheek
Copy link

JoshCheek commented Apr 19, 2018

I initially reported this issue here.

Description

When I pipe bash -i into a function (in this case, grep), the process gets stopped. @faho did some investigating and said:

The problem with bash -i seems to be that it grabs the terminal for itself - strace -e ioctl shows it doing one with TIOCSPGRP - which is the underlying syscall for tcsetpgrp on linux.
-- #1362 (comment)

My environment

$  fish --version
fish, version 2.7.1

$ echo $version
2.7.1

$ uname -a
Darwin Joshs-MacBook-Air-2.local 15.6.0 Darwin Kernel Version 15.6.0: Mon Aug 29 20:21:34 PDT 2016; root:xnu-3248.60.11~1/RELEASE_X86_64 x86_64

$ echo $TERM
xterm-256color

Demo / how to reproduce

# ===== Setup =====

# get a clean environment
$ sh -c 'env HOME=$(mktemp -d) fish'
Welcome to fish, the friendly interactive shell

# shorten the prompt
josh@Joshs-MacBook-Air-2 /U/josh> function fish_prompt; echo '> '; end


# ===== Demo the issue =====

# hangs (I'll press C-c)
> bash -i -c 'echo hello >&2' | grep whatever
Job 1, 'bash -i -c 'echo hello >&2' | g…' has stopped

# its state is "stopped"
> jobs
Job	Group	State	Command
1	24863	stopped	bash -i -c 'echo hello >&2' | grep whatever

# when I foreground it, it completes as expected
> fg
Send job 1, 'bash -i -c 'echo hello >&2' | grep whatever' to foreground
hello


# ===== Slight variations that don't exhibit the issue =====

# use the grep command instead of the function
> bash -i -c 'echo hello >&2' | command grep whatever
hello

# run bash without the -i flag
> bash -c 'echo hello >&2' | grep whatever
hello


# ===== Other potentially useful info =====

# the grep function
> type grep
grep is a function with definition
function grep
    command grep --color=auto $argv
end
@faho

This comment has been minimized.

Copy link
Member

faho commented Apr 19, 2018

Okay, this is another issue related to #4540, #4653.

  • Fish starts a "keepalive" process that gets its own process group.

  • Fish starts bash in the keepalive's pgroup.

  • Fish goes on to start grep, and because it is inside a function loses track of the old job and starts it in a new job and hence its own pgroup. It assigns control of the terminal to grep.

  • With "-i", bash grabs control of the terminal for its pgroup, away from grep.

  • Bash doesn't read from or write to the terminal

  • grep does, and receives SIGTTOU, which stops it

  • The pipeline hangs

@JoshCheek

This comment has been minimized.

Copy link

JoshCheek commented Apr 19, 2018

Oh, note that in my example the bash process writes to stderr, and grep writes to stdout. It's leftover context from the initial process I was debugging.

I just checked, and it doesn't seem to matter, though, this has the same issue:

$ bash -ic '' | grep x
@JoshCheek

This comment has been minimized.

Copy link

JoshCheek commented Apr 19, 2018

Another example to make the function thing clearer:

# Start: iterate over each line of input and print it out.
# There is no input, so it completes the iteration and exits
$ bash -ic '' | ruby -e '$stdin.each_line { |l| p l }'

# Now we put the RHS into a function
$ function x; ruby -e '$stdin.each_line { |l| p l }'; end

# When we pipe to that function instead, it hangs.
# When I press C-c, it sends an interrupt, Ruby dies, something gets stopped
$ bash -ic '' | x
^CTraceback (most recent call last):
	1: from -e:1:in `<main>'
-e:1:in `each_line': Interrupt
Job 6, 'bash -ic '' | x' has stopped
@benitogf

This comment was marked as off-topic.

Copy link

benitogf commented Jun 11, 2018

hello not sure if it's the right thread to ask but is there a way to do something like diff <(echo "fish") <(echo "bash") ?

@faho

This comment was marked as off-topic.

Copy link
Member

faho commented Jun 11, 2018

hello not sure if it's the right thread to ask

@benitogf: Usually, you'd either open a new issue here (we do allow questions) or you'd ask on https://gitter.im/fish-shell/fish-shell.

Anyway, fish does not have the <(command) syntax ("process substitution"). Instead, it has the psub function, that allows it to be written as (command | psub). So this would translate to diff (echo fish | psub) (echo bash | psub).

@benitogf

This comment was marked as off-topic.

Copy link

benitogf commented Jun 12, 2018

@faho thanks for the quick reply 🥇

@faho faho added the bug label Sep 22, 2018

@faho faho added this to the fish-future milestone Sep 22, 2018

@faho

This comment has been minimized.

Copy link
Member

faho commented Oct 25, 2018

This seems to be fixed via #5219.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment