6

There are many discussions on this: Pipe output to bash function

I just want to know why:

  #bin/sh
  function myfunc () {
      echo $1
  }

  ls -la | myfunc

will give empty line. May I ask that why isn't our output of ls not treated as $1 as the function? What is the mechanism behind this?

If we try:

  #bin/sh
  function myfunc () {
      i=${*:-$(</dev/stdin)}
      echo $i
  }

  ls -la | myfunc

Then we have:

total 32 drwxr-xr-x 6 phil staff 204 Sep 11 21:18 . drwx------+ 17 phil staff 578 Sep 10 21:34 .. lrwxr-xr-x 1 phil staff 2 Sep 10 21:35 s1 -> t1 lrwxr-xr-x 1 phil staff 2 Sep 10 21:35 s2 -> t2 lrwxr-xr-x 1 phil staff 2 Sep 10 21:35 s3 -> t3 -rwxr-xr-x 1 phil staff 96 Sep 11 21:39 test.sh

which does not keep the actual format of ls -la (with \n).

What is the correct/proposed way to pass a command output to your function as a parameter as it is?

Thanks

Update +John Kugelman

  #bin/sh
  function myfunc () {
    cat | grep "\->"  | while read line
    do
        echo $line
    done


    cat | grep "\->"  | while read line
    do
        echo "dummy"
    done
      }

  ls -la | myfunc

This will only print once. What if we would like to use the result twice (store it as a variable possible?)

Thanks,

Tom Lau
  • 109
  • 1
  • 7

1 Answers1

16

There are two different ways functions can receive input:

  • Command-line arguments: $1, $2, etc.
  • Standard input.

When you pipe output from one command to another, it's received on stdin, not as arguments. To read it you could do one of these:

myfunc() {
    cat
}

myfunc() {
    local line
    while IFS= read -r line; do
        printf '%s\n' "$line"
    done
}
ls -la | myfunc

If you want to leave your function as is and it expects $1 to be set, you'll need to change from a pipe to command substitution.

myfunc() {
    echo "$1"
}
myfunc "$(ls -la)"

Notice the abundant use of double quotes. Make sure you write echo "$1" with quotes or else the newlines will be mangled.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • Thanks for the reply. For the `cat` one, may I ask that why can't we cat twice? What if we would like to re-use this code? (I will add code details in the question description again.) – Tom Lau Sep 11 '18 at 14:02
  • 3
    You can only read stdin once. If you want to process it twice you need to save it in a variable or temporary file. Best practice is to do everything in one pass so you don't have to save it off. I'd say post this as a new question rather than updating this one. It'll help if you post exactly what you're trying to do so we can suggest the best way to combine the two loops into one. – John Kugelman Sep 11 '18 at 14:12