如何制作一个可以从标准输入读取的bash功能?

JBo*_*Boy 42 bash stdin pipe

我有一些脚本,用参数工作,他们工作得很好,但我想他们能够从标准输入读取,例如从一个管道,一个例子,假设这就是所谓的读:

#!/bin/bash
function read()
{
 echo $*
}

read $*
Run Code Online (Sandbox Code Playgroud)

现在这适用read "foo" "bar",但我想用它作为:

echo "foo" | read
Run Code Online (Sandbox Code Playgroud)

我该如何做到这一点?

fed*_*qui 39

您可以使用它<<<来获取此行为.read <<< echo "text"应该成功.

测试readly(我不喜欢使用保留字):

function readly()
{
 echo $*
 echo "this was a test"
}

$ readly <<< echo "hello"
hello
this was a test
Run Code Online (Sandbox Code Playgroud)

使用管道,根据"Bash脚本的答案,从stdin管道读取值":

$ echo "hello bye" | { read a; echo $a;  echo "this was a test"; }
hello bye
this was a test
Run Code Online (Sandbox Code Playgroud)

  • 第二个示例将丢弃其标准输入的第一行之后的所有内容. (6认同)
  • 在第一个例子中,您实际上只是将"echo"一词提供给`readly`的标准输入,它忽略了它的标准输入,并将第一个参数设置为"hello".您可以将"echo"更改为任何其他单个单词并获得相同的结果. (4认同)

che*_*ner 37

编写一个可以读取标准输入的函数有点棘手,但是在没有给出标准输入时可以正常工作.如果您只是尝试从标准输入读取,它将阻塞,直到它收到任何,就像您只需cat在提示符处输入一样.

在bash 4中,你可以通过使用参数为0 -t来解决这个问题.read如果有任何输入可用,它会成功,但不会消耗任何输入; 否则,它失败了.

这是一个简单的函数,就像cat它有任何来自标准输入的东西,echo否则.

catecho () {
    if read -t 0; then
        cat
    else
        echo "$*"
    fi
}

$ catecho command line arguments
command line arguments
$ echo "foo bar" | catecho
foo bar
Run Code Online (Sandbox Code Playgroud)

这使得标准输入优先于命令行参数,即echo foo | catecho bar输出foo.要使参数优先于标准输入(echo foo | catecho bar输出bar),可以使用更简单的函数

catecho () {
    if [ $# -eq 0 ]; then
        cat
    else
        echo "$*"
    fi
}
Run Code Online (Sandbox Code Playgroud)

(它还具有使用任何 POSIX兼容外壳的优势,而不仅仅是某些版本bash).

  • 我已经设法让这个在我的系统上工作:'如果读-t 0.00001 STDIN; 然后回显"$ STDIN"'工作的最小超时时间似乎至少取决于CPU速度,也可能取决于系统负载.像0.01或0.001这样的值可能是相当可靠的. (5认同)
  • 关于如何在bash 3中执行此操作的任何提示? (2认同)
  • 没什么简单的.我想你需要尝试在后台读取标准输入,然后在一秒钟之后将其删除,如果尚未完成,则尝试确定它是否读取任何内容.我不确定如何以一种万无一失的方式做到这一点(子壳中存在变量问题,处理标准输入的部分读取和竞争条件). (2认同)

And*_*ndy 14

将许多其他答案组合成对我有用的东西(这个人为的例子将小写输入变为大写):

  uppercase() {
    local COMMAND='tr [:lower:] [:upper:]'
    if [ -t 0 ]; then
      if [ $# -gt 0 ]; then
        echo "$*" | ${COMMAND}
      fi
    else
      cat - | ${COMMAND} 
    fi
  }
Run Code Online (Sandbox Code Playgroud)

一些例子(第一个没有输入,因此没有输出):

:; uppercase
:; uppercase test
TEST
:; echo test | uppercase 
TEST
:; uppercase <<< test
TEST
:; uppercase < <(echo test)
TEST
Run Code Online (Sandbox Code Playgroud)

一步步:

  • `[ -t 0 ]` 在某些情况下对我来说失败(例如从 git-hook 中调用脚本)。我用`[!-p /dev/stdin ]` 并且能够让它在更广泛的情况下工作。 (2认同)

ken*_*orb 5

这是sprintfbash中使用printf和标准输入的函数的示例实现:

sprintf() { local stdin; read -d '' -u 0 stdin; printf "$@" "$stdin"; }
Run Code Online (Sandbox Code Playgroud)

用法示例:

$ echo bar | sprintf "foo %s"
foo bar
Run Code Online (Sandbox Code Playgroud)

这将让您了解函数如何从标准输入读取.


zwb*_*etz 5

这里的聚会迟到了。根据 的@andy答案这是我定义to_uppercase函数的方式。

  • 如果 stdin 不为空,则使用 stdin
  • 如果 stdin 为空,则使用 args
  • 如果 args 为空,则不执行任何操作
to_uppercase() {
  local input="$([[ -p /dev/stdin ]] && cat - || echo "$@")"
  [[ -n "$input" ]] && echo "$input" | tr '[:lower:]' '[:upper:]' 
}
Run Code Online (Sandbox Code Playgroud)

用途:

$ to_uppercase 
$ to_uppercase abc
ABC
$ echo abc | to_uppercase 
ABC
$ to_uppercase <<< echo abc 
ABC

Run Code Online (Sandbox Code Playgroud)

Bash 版本信息:

$ bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)
Run Code Online (Sandbox Code Playgroud)