パラメータを操作するスクリプトがいくつかありますが、問題なく動作しますが、標準入力から、たとえばパイプから読み取ることができるようにしたいと思います。たとえば、これが read と呼ばれるとします。
#!/bin/bash
function read()
{
echo $*
}
read $*
これで動作しますread "foo" "bar"
が、次のように使用したいと思います。
echo "foo" | read
どうすればこれを達成できますか?
標準入力を読み取ることができる関数を作成するのは少し難しいですが、標準入力が指定されていない場合でも適切に機能します。単純に標準入力から読み取ろうとすると、プロンプトで単純に入力した場合と同様に、何かを受け取るまでブロックさcat
れます。
-t
bash 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
ますfoo
。echo foo | catecho bar
引数を標準入力 (出力)よりも優先させるにbar
は、より単純な関数を使用できます。
catecho () {
if [ $# -eq 0 ]; then
cat
else
echo "$*"
fi
}
(特定のバージョンの だけでなく、POSIX 互換シェルで動作するという利点もありますbash
)。
他の多くの回答を組み合わせて、私にとってうまくいったものにします(この不自然な例では、小文字の入力が大文字に変わります):
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}
ここでパーティーに遅刻。@andy
のanswerから構築して、関数を定義する方法を次に示しto_uppercase
ます。
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)
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