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

时间:2013-09-12 10:01:37

标签: bash pipe stdin

我有一些使用参数的脚本,它们工作得很好,但我希望它们能够从stdin中读取,例如管道,例如,假设这被称为read:

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

read $*

现在这适用于read "foo" "bar",但我想将其用作:

echo "foo" | read

我如何做到这一点?

7 个答案:

答案 0 :(得分:39)

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

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

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

$ readly <<< echo "hello"
hello
this was a test

使用管道,基于this answer to "Bash script, read values from stdin pipe"

$ echo "hello bye" | { read a; echo $a;  echo "this was a test"; }
hello bye
this was a test

答案 1 :(得分:36)

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

在bash 4中,您可以使用参数为0的-t read选项解决此问题。如果有任何输入可用,但不消耗任何输入,则成功;否则,它会失败。

这是一个简单的函数,如果它有标准输入的任何内容,就像cat一样,否则echo。{/ p>

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

$ catecho command line arguments
command line arguments
$ echo "foo bar" | catecho
foo bar

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

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

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

答案 2 :(得分:13)

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

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

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

:; uppercase
:; uppercase test
TEST
:; echo test | uppercase 
TEST
:; uppercase <<< test
TEST
:; uppercase < <(echo test)
TEST

一步一步:

  • 测试终端是否打开了文件描述符0(/dev/stdin

    if [ -t 0 ]; then
    
  • 测试CLI调用参数

    if [ $# -gt 0 ]; then
    
  • 回显命令

    的所有CLI参数
    echo "$*" | ${COMMAND}
    
  • 如果管道stdin(即不是终端输入),则输出stdin到命令(cat -catcat /dev/stdin的简写)

    else
      cat - | ${COMMAND}
    

答案 3 :(得分:5)

以下是使用sprintf和标准输入的bash中printf函数的示例实现:

sprintf() { local stdin; read -d '' -u 0 stdin; printf "$@" "$stdin"; }

使用示例:

$ echo bar | sprintf "foo %s"
foo bar

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

答案 4 :(得分:0)

我发现可以使用btn.isTreasure()test在一行中完成此操作...

awk

test -p /dev/stdin && awk '{print}' /dev/stdin 测试管道输入,通过stdin接受输入。只有输入存在才能运行test -p,否则它将无限期地挂起,等待永远不会出现的输入。

我已将此功能放入功能中以便于使用...

awk

...用法

inputStdin () {
  test -p /dev/stdin  && awk '{print}' /dev/stdin  && return 0
  ### accepts input if any but does not hang waiting for input
  #
  return 1
}

另一个函数使用awk而不进行测试等待命令行输入......

_stdin="$(inputStdin)"

...用法

inputCli () {
  local _input=""
  local _prompt="$1"
  #
  [[ "$_prompt" ]]  && { printf "%s" "$_prompt" > /dev/tty; }
  ### no prompt at all if none supplied
  #
  _input="$(awk 'BEGIN {getline INPUT < "/dev/tty"; print INPUT}')"
  ### accept input (used in place of 'read')
  ###   put in a BEGIN section so will only accept 1 line and exit on ENTER
  ###   WAITS INDEFINITELY FOR INPUT
  #
  [[ "$_input" ]]  && { printf "%s" "$_input"; return 0; }
  #
  return 1
}

请注意,在命令替换_userinput="$(inputCli "Prompt string: ")" 中调用函数时,似乎需要第一个> /dev/tty上的printf来获取打印提示。

$(...)的这种使用允许消除用于从键盘或标准输入收集输入的奇怪awk命令。

答案 5 :(得分:0)

在这里晚聚会。以@andy的{​​{3}}为基础,这就是我定义to_uppercase函数的方式。

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

用法:

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

bash版本信息:

$ bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)

答案 6 :(得分:0)

另一个版本:

  1. 通过管道或参数传递文本
  2. 通过更改最后一行的命令轻松复制和粘贴
  3. 在 bash、zsh 中工作
window.location.reload(true)

用法:

`     <p-table ...>
        <ng-template pTemplate="colgroup" let-columns>
        <colgroup>
            <col *ngFor="let col of columns" style="width: 40px;">
        </colgroup>
        </ng-template>
       </p-table>`