45

パラメータを操作するスクリプトがいくつかありますが、問題なく動作しますが、標準入力から、たとえばパイプから読み取ることができるようにしたいと思います。たとえば、これが read と呼ばれるとします。

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

read $*

これで動作しますread "foo" "bar"が、次のように使用したいと思います。

echo "foo" | read

どうすればこれを達成できますか?

4

7 に答える 7

42

標準入力を読み取ることができる関数を作成するのは少し難しいですが、標準入力が指定されていない場合でも適切に機能します。単純に標準入力から読み取ろうとすると、プロンプトで単純に入力した場合と同様に、何かを受け取るまでブロックさcatれます。

-tbash 4 では、オプション toを引数 0 とともに使用することで、これを回避でき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

これにより、標準入力がコマンドライン引数よりも優先されecho foo | catecho barますfooecho foo | catecho bar引数を標準入力 (出力)よりも優先させるにbarは、より単純な関数を使用できます。

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

(特定のバージョンの だけでなく、POSIX 互換シェルで動作するという利点もありますbash)。

于 2013-09-12T14:18:47.200 に答える
15

他の多くの回答を組み合わせて、私にとってうまくいったものにします(この不自然な例では、小文字の入力が大文字に変わります):

  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 -andcatは の省略形ですcat /dev/stdin)

    else
      cat - | ${COMMAND}
    
于 2016-05-29T15:26:39.060 に答える
4

ここでパーティーに遅刻。@andyanswerから構築して、関数を定義する方法を次に示し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 --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)
于 2019-06-25T21:08:38.770 に答える
0

testこれは、and awk...を使用して 1 行で実行できることがわかりました。

    test -p /dev/stdin  && awk '{print}' /dev/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
}

使用法...

_stdin="$(inputStdin)"

別の関数は、テストなしで awk を使用して、コマンドライン入力を待機します...

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関数が Command Substituion で呼び出されたときにプロンプ​​トを表示するには、最初printfに が必要であることに注意してください$(...)

をこのように使用すると、キーボードまたは標準入力から入力を収集するためawkの風変わりなコマンドを排除できます。read

于 2018-05-11T19:04:33.420 に答える