Skip to content
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

psub for long-running commands - fish vs zsh/bash #4751

Closed
czak opened this issue Feb 25, 2018 · 3 comments
Closed

psub for long-running commands - fish vs zsh/bash #4751

czak opened this issue Feb 25, 2018 · 3 comments
Labels

Comments

@czak
Copy link

czak commented Feb 25, 2018

I'm trying to use psub to feed a long-running process' output into another.

To simplify:

# fish
$ cat (begin; echo First; sleep 5; echo Second; end | psub)
# nothing appears for 5 seconds ...
First
Second
$

With zsh/bash, the First line of output is immediately available to cat.
And this is the behavior I'm hoping to achieve:

# zsh
$ cat <(echo First; sleep 5; echo Second)
First
# ^ this appears immediately, then waits 5 seconds...
Second

Is it supported in fish? Am I missing something?

I tried both psub and psub -F.
I'm using fish 2.7.1.

@faho
Copy link
Member

faho commented Feb 25, 2018

psub has some issues. In this case you're hitting #1040 - it fully writes the file before returning.

The question I have here is why you're using it. Usually the easiest way to get a command to accept data from another is to simply pipe it. So instead of command1 (command2 | psub), you'd do command2 | command1 or perhaps command2 | command1 -.

If there really is no way to get command1 to read from stdin, you can use mkfifo:

mkfifo /tmp/fifo
command2 >/tmp/fifo &
command1 /tmp/fifo

which is basically what psub is supposed to do in the background.

@czak
Copy link
Author

czak commented Feb 26, 2018

Thanks for the reply @faho!

My use case is this: I'm implementing a command1 (from your examples).
It's an interactive terminal program which needs input from both:

  • a continuous stream of text (ideally, as stdin coming from command2's stdout)
  • keyboard

A real-world use case would look like this:

$ rails server | my_interactive_app

The idea is that rails server keeps producing output, and my_interactive_app receives it at stdin, while continuously accepting keyboard input from the user. It's a bit tricky to get piped stdin and keyboard working at the same time, but I managed to get past that.

But then I ran into another challenge, simplified to:

$ begin; sleep 10; echo "Some output"; sleep 10; end | true

This blocks the entire pipeline for 10 seconds, even though true exits immediately.
In my case (rails server | my_interactive_app), it's very possible that rails server will not be producing any output for periods of time, and I want to be able to quit my_interactive_app at any time. However, quitting returns to console only when rails server tries to produce some output (i.e. not immediately).

Note: I recognize I don't know much about pipes and might be missing something trivial.

Process substitution (on bash/zsh for now) is free of this "lock". my_interactive_app <(rails server) allows me to quit my_interactive_app at any time. However, this keeps rails server running in the background, which is not ideal either.

tl;dr

I'm looking for a clean way to:

  • pipe command2 | command1
  • allow continuous stream of output from command2
  • allow command1 to close the pipe (or terminate command2?) when it decides to

@czak
Copy link
Author

czak commented Feb 26, 2018

Ah the power of rubberducking :)

I think what I really need is this syntax instead:

$ my_interactive_app rails server

I can have my_interactive_app spawn and control the rails server process and its output. It's more work for my_interactive_app, but the syntax is even cleaner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants