0

Really hoping someone can help me to understand this behavior and how to work around it.

> functions hello
# Defined in ...
function hello
    echo -n $argv[1] "hello"
end
> functions world
# Defined in ...
function world
    echo -n "world"
end
> hello
hello⏎ 

> world
world⏎ 

> world | hello
hello⏎ 
  • 3
    Since function hello never reads its input, it ends up being discarded. What do you expect to happen? – Chris Dodd Feb 19 '21 at 23:01
  • Chris, this is simply the latest thing I tried, my best guess as to how to pass arguments, from one function to another, using a pipe. I've tried everything I could think of to make this work, thought I would see if anyone had any ideas. Using (read) and capturing stdin to a variable does not produce the desired results, either. – David Shepard Feb 20 '21 at 05:38
  • You pass arguments to a function as arguments (same way you pass arguments to any command or program). If you would say what you are trying to do, maybe someone could help you. – Chris Dodd Feb 20 '21 at 09:50

2 Answers2

2

You have misunderstood how the $argv function local variable is initialized. It is not set to the contents of stdin. It is set to the positional arguments of the function. For example, hello (world) will produce the output you expect. If you want your edit function to capture its data from stdin you need to explicitly read stdin.

Kurtis Rader
  • 6,734
  • 13
  • 20
  • There is no way to pass arguments, from one function to another, using a pipe? – David Shepard Feb 20 '21 at 05:36
  • Correct. You can pass arguments via output capture (such as `hello (world)` which does involve an implicit pipe. But you can't pass CLI args via an explicit pipe. – Kurtis Rader Feb 20 '21 at 23:12
1

As @Kurtis-Rader's answer mentioned, to access a pipe in a fish function, you use the read command (see man read). This is similar to bash, sh, zsh, etc.

Example for fish (with edits discussed in the comments to make the piped input optional):

function greeting
    echo "Good Morning"
end

function world
    if isatty stdin
        set greetstring "Hello"
    else
        read greetstring
    end
    echo (string trim $greetstring)", World"
end

> greeting | world
Good Morning, World

> world
Hello, World

To read multiline input from a pipe, you wrap the read in a while statement.

NotTheDr01ds
  • 15,620
  • 5
  • 44
  • 70
  • Thanks for this. I stumbled across this also and it almost works, except that read blocks on input. I can't seem to find any method of telling read not to block, or a way to "peek" at stdin and not read if it's empty. In other words, to use read in this way, the function now is incapable of being used outside of the pipe operation. This behavior seems very odd. – David Shepard Feb 20 '21 at 14:34
  • See [this answer](https://stackoverflow.com/a/58860287/11810933) for a method on how to make the piped input optional. I haven't tried it myself, but I think it is basically saying "Always wrap the `read` in a `while`, store the result in a variable, and check that". That way, if there is no input, the while loop will terminate and allow the function to continue. – NotTheDr01ds Feb 20 '21 at 14:40
  • Actually, I like the [first answer](https://stackoverflow.com/a/58137232/11810933) on that question (checking `atty`) better. I've edited my examples to use that method. – NotTheDr01ds Feb 20 '21 at 15:00
  • Thanks, NotTheDro1ds! It's a little wonky, but it works. For my case, I just went with 'isatty stdin', which gets to the behavior I was looking for. Function works with a pipe and as a standalone function when not in the pipe. – David Shepard Feb 20 '21 at 15:16
  • Yes, this is much better. It's a bit unintuitive for any who tries this the first time, but it gets the job done. Again, thanks. I much prefer composing functions like this. – David Shepard Feb 20 '21 at 15:18
  • 1
    Good to hear it's working for you. Please remember to accept/upvote. As for unintuitive, I agree, but the bash [solution](https://stackoverflow.com/a/35512655/11810933) looks so, so much worse ;-). – NotTheDr01ds Feb 20 '21 at 16:17