プロセスの標準出力を独自の標準入力にリダイレクト

プロセスの標準出力を独自の標準入力にリダイレクト

私はHaskellの自己参照リストについて考えています。たとえば、次のスクリプトがありますfibonacci.hs

#!/usr/bin/env runghc

fibs :: [Integer]
fibs = 1:1:(zipWith (+) fibs $ tail fibs)

main :: IO ()
main = do
    mapM_ print $ take 50 fibs

ファイル拡張子が非常に似ているので(少しxp)、プロセスの標準出力を独自の標準入力に追加するシェルスクリプトに似たものが必要であると推論しました。私が考えることができるものは次のとおりですfibonacci.sh

#!/usr/bin/env sh

{ echo 1; echo 1; } > fibonaccis

tail -f fibonaccis |
    python3 -c 'if True: # dummy to fix indentation
        b = int(input())
        for _ in range(48):
            a, b = b, int(input())
            print(a + b)' >> fibonaccis

cat fibonaccis

ただし、すべてをファイルに書き込む必要があるため、やや満足できません。明らかに、これは既知のアルゴリズムがより最適化されたおもちゃの例ですが、1000番目のフィボナッチ数を生成したい場合はどうすればよいですか? Pythonスクリプトが標準出力を使用している場合は、それを保存する必要はありません。

それでは、ファイルを使用してこれを行うより良い方法はありますか、それとも理想的にはファイルなしでリダイレクトを使用してこれを行う方法はありますか?それともこれは本当に悪い考えですか?名前付きパイプを介してこれを実行できますか?

何を検索しようとしても、私はプロセスの標準出力を他のプロセスの標準入力に追加する方法だけを見つけます。これはすでにある程度慣れています。双方向パイプも私が望むものではないようです。

プロセスがI / Oをあまりバッファリングしないように注意が必要であることを理解してください。

答え1

〜のようにMatthew Guntherは彼の答えで指摘しました。、ㅏ名前付きパイプ("fifo") を使用すると、スクリプトが独自の出力を読み取ることができます。

#!/bin/bash

# Create pipe and arrange to remove it when done.
mkfifo mypipe
trap 'rm -f mypipe' EXIT

# Just to start off the sequence. Note that this
# needs to be a background process to avoid
# blocking, as there is nobody reading from the
# pipe yet.
echo '0 1' >mypipe &

# Numbers to produce. Note that the produced numbers
# will overflow at n=93.
n=48

# Read the two numbers from the pipe and put the
# last of these back together with the next number
# in the sequence:
while [ "$n" -gt 0 ] && read a b; do
        c=$(( a + b ))
        printf '%d %d\n' "$b" "$c" >&3

        # Also print the "b" number as output.
        printf '%d\n' "$b"

        n=$(( n - 1 ))
done <mypipe 3>mypipe

ループのパイプに書き込むために追加のファイル記述子を使用しました。これは結果のシーケンスを通常の出力ストリーム(そしてこの目的のために標準エラーストリームをオーバーロードしません)。

Pythonコードをこのように使用したい場合は、次のことができます。それはまるで

#!/bin/bash

mkfifo mypipe
trap 'rm -f mypipe' EXIT

printf '%d\n%d\n' 0 1 >mypipe &

python3 -c 'if True: # dummy to fix indentation
    b = int(input())
    for _ in range(48):
        a, b = b, int(input())
        print(a + b)' <mypipe >mypipe

このスクリプトでは、どの出力も得られないことがわかります。これは、Pythonコードの出力を独自の入力として使用するためです。端末からいくつかの出力を取得するには、上記のシェルループで同様の操作を行います(標準出力以外のものに書き込む)。

#!/bin/bash

mkfifo mypipe
trap 'rm -f mypipe' EXIT

printf '%d\n%d\n' 0 1 >mypipe &

python3 -c '
import sys
b = int(input())
for _ in range(48):
    a, b = b, int(input())
    print(a + b)
    print(b, file=sys.stderr)' <mypipe >mypipe

ここでは、標準エラーストリームを(乱用)使用して端末のユーザーに実際の結果を提供します。最初のバリエーション(新しいファイルディスクリプタを介したパイプの出力処理)のようにシェルループを実行すると、よりきれいになりますが、Pythonの知識が深刻です。

関連情報