88

私はbashスクリプトに単純な機能を持っており、stdoutを入力としてパイプしたいと思います。

jc_hms(){
  printf "$1"
}

こんな感じで使いたいです。

var=`echo "teststring" | jc_hms`

もちろん、冗長な関数 echo と printf を使用して質問を単純化しましたが、アイデアはわかります。現在、「見つかりません」というエラーが表示されます。これは、パラメーターの区切りが間違っていることを意味していると思います (「$1」の部分)。助言がありますか?

もともと jc_hms 関数は次のように使用されていました。

echo `jc_hms "teststring"` > //dev/tts/0

しかし、シリアルポートに送信する前に、最初にさらに処理するために結果を変数に保存したいと思います。

編集:明確にするために、シリアルポートに出力しようとしているわけではありません。「|」が必要な場合はbash関数にインターフェースしたいと思います パイプ文字、これが可能かどうか疑問に思っています。

編集:さて、これが完全な機能です。

jc_hms(){
  hr=$(($1 / 3600))
  min=$(($1 / 60))
  sec=$(($1 % 60))

  printf "$hs:%02d:%02d" $min $sec
}

関数を使用して、このコード行の文字列を形成しています

songplaytime=`echo $songtime | awk '{print S1 }'`
printstring="`jc_hms $songplaytime`"  #store resulting string in printstring

$songtime は、スペースで区切られた "playtime totaltime" として表される文字列です。

これを1行で実行して、awkの後にパイプできたらいいのにと思います

printstring=`echo $songtime | awk '{print S1 }' | jc_hms`

そのようです。

4

8 に答える 8

83

実際の質問に答えるために、シェル関数がパイプの受信側にある場合、標準入力は関数内のすべてのコマンドに継承されますが、標準入力から実際に読み取るコマンドのみがデータを消費します。次々に実行されるコマンドの場合、後のコマンドは、前のコマンドによって消費されなかったものだけを見ることができます。2 つのコマンドが並行して実行される場合、どのコマンドがどのデータを参照するかは、OS がコマンドをスケジュールする方法によって異なります。

printf関数内の最初で唯一のコマンドであるため、標準入力は事実上無視されます。readに渡すことができる変数に標準入力を読み込むためにビルトインを使用するなど、いくつかの方法がありますprintf

jc_hms () {
    read foo
    hr=$(($foo / 3600))
    min=$(($foo / 60))
    sec=$(($foo % 60))
    printf "%d:%02d:%02d" "$hr" "$min" "$sec"
}

ただし、パイプラインの必要性は、 を使用する必要性に依存しているように思われるためawk、次の代替案を提案させてください。

printstring=$( jc_hms $songtime )

songtimeはスペースで区切られた数値のペアで構成されているため、シェルは の値に対してワード分割を実行し、2つの別個のパラメーターsongtimeを認識します。jc_hmsこれには の定義を変更する必要はなく、jc_hms標準入力を介して何かをパイプする必要もありません。

それでも標準入力を読む別の理由がある場合は、jc_hmsお知らせください。

于 2012-07-12T17:20:04.333 に答える
62

そのようなものを bash 関数に直接パイプすることはできませんがread、代わりにそれをプルするために使用できます。

jc_hms() {
  while read -r data; do
      printf "%s" "$data"
  done
}

あなたが望むものであるべきです

于 2012-07-12T14:49:19.377 に答える
57

1) 私はこれがかなり古い投稿であることを知っています

2) 私はここの答えのほとんどが好きです

しかし、似たようなものが必要だったので、この投稿を見つけました。stdin を使用する必要があることに誰もが同意しますが、ここでの回答に欠けているのは、/dev/stdin ファイルの実際の使用法です。

read ビルトインを使用すると、この関数をパイプ入力で使用することが強制されるため、通常の方法では使用できなくなります。/dev/stdin を利用することは、この問題を解決する優れた方法だと思うので、完全を期すために 2 セント追加したいと思います。

私の解決策:

jc_hms() { 
  declare -i i=${1:-$(</dev/stdin)};
  declare hr=$(($i/3600)) min=$(($i/60%60)) sec=$(($i%60));
  printf "%02d:%02d:%02d\n" $hr $min $sec;
}

実際に:

user@hostname:pwd$ jc_hms 7800
02:10:00
user@hostname:pwd$ echo 7800 | jc_hms 
02:10:00

これが誰かを助けることを願っています。

ハッピーハッキング!

于 2016-02-19T18:44:27.750 に答える
26

または、簡単な方法で行うこともできます。

jc_hms() {
    cat
}

これまでのすべての回答は、これがOPが望んでいたものではないという事実を無視していますが(彼は機能が単純化されていると述べました)

于 2012-07-12T15:26:00.413 に答える
17

Bash組み込みの条件付き unset 置換構文を使用した user.friendly の回答が気に入っています。不確定なパラメーター数の場合など、彼の答えをより一般的なものにするためのわずかな調整を次に示します。

function myfunc() {
    declare MY_INPUT=${*:-$(</dev/stdin)}
    for PARAM in $MY_INPUT; do
        # do what needs to be done on each input value
    done
}
于 2016-04-05T17:16:52.637 に答える
1

提案されたソリューションでは、条件付きでのみ呼び出されるstdinか、コンテンツが必要です。readそうしないと、関数はコンソールからのコンテンツを待機し、続行する前にEnterまたはCtrl+が必要になります。D

read回避策は、タイムアウトを使用することです。例えばread -t <seconds>

function test ()
{
  # ...
  # process any parameters
  # ...
  read -t 0.001 piped
  if [[ "${piped:-}" ]]; then
    echo $piped
  fi
}

注、私に-t 0はうまくいきませんでした。
タイムアウトに別の値を使用する必要がある場合があります。値が小さすぎるとバグが発生する可能性があり、タイムアウトが大きすぎるとスクリプトが遅延します。

于 2020-05-05T10:34:40.187 に答える