为什么管道输出到bash函数中不起作用

Tom*_*Lau 1 unix linux bash shell pipe

关于此有许多讨论:将输出输出到bash函数

我只想知道为什么:

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

  ls -la | myfunc
Run Code Online (Sandbox Code Playgroud)

将给空行。请问为什么我们的输出ls不被视为$1函数?其背后的机制是什么?

如果我们尝试:

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

  ls -la | myfunc
Run Code Online (Sandbox Code Playgroud)

然后我们有:

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

不会保留ls -la(\ n)的实际格式。

将命令输出原样作为参数传递给函数的正确/建议方法是什么?

谢谢

更新+约翰·库格曼

  #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
Run Code Online (Sandbox Code Playgroud)

这只会打印一次。如果我们想两次使用结果(将其存储为变量)怎么办?

谢谢,

Joh*_*ica 5

函数可以通过两种不同的方式接收输入:

  • 命令行参数:$1$2,等。
  • 标准输入。

当您将输出从一个命令传递到另一个命令时,它是在stdin上接收的,而不是作为参数接收的。要阅读它,您可以执行以下操作之一:

myfunc() {
    cat
}

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

如果您希望按原样保留函数并希望$1对其进行设置,则需要从管道替换为命令替换。

myfunc() {
    echo "$1"
}
Run Code Online (Sandbox Code Playgroud)
myfunc "$(ls -la)"
Run Code Online (Sandbox Code Playgroud)

请注意大量使用双引号。确保echo "$1"使用引号书写,否则换行符将被修饰。

  • 您只能读取 stdin 一次。如果您想处理它两次,您需要将其保存在变量或临时文件中。最佳实践是一次完成所有操作,这样您就不必保存它。我想说将其作为一个新问题发布,而不是更新这个问题。如果您准确地发布您想要执行的操作,这将会有所帮助,以便我们可以建议将两个循环合并为一个循环的最佳方法。 (3认同)