パイプ接続

パイプ接続

次のルーチンを考えてみましょう。

alpha() { echo a b c |tr ' ' '\n'; }

pasteストリームを出力し、出力ストリームをインポートして変換し、元の出力ストリームと一緒に使用したいと思います。

たとえば、upcasingを使用して変換すると、次のように必要なものが得られます。

$ mkfifo p1 p2
$ alpha | tee p1 >( tr a-z A-Z > p2) >/dev/null &
$ paste p1 p2
a       A
b       B
c       C

私の質問はこれを行うより良い方法がありますか?可能であれば、名前付きパイプを含めない方法はありますか?

ベストアンサー1

ほとんどの unice では、デバイスリンクを介してファイル記述子を参照できます。

alpha(){ echo a b c | tr \  \\n; }
alpha | { alpha |
    tr \[:lower:] \[:upper:] |
    paste - /dev/fd/9
}   9<&0

A   a
B   b
C   c

名前付きパイプ


まあ、すでにうまく動作するバージョンがあります。私のエディタで開いているバージョン(未完了)現時点では実現可能ではありません。オプション全体を複数の部分に分析し、私の意図だけを曖昧に覚えています。しかし、これは...

_p(){   : "$((_$$=0))"
    cd -P -- "${TMPDIR:-/tmp}"          &&
    while   [ -h "$$.$((_$$+=$$))" ]    ||
            [ -e "$$.$((_$$))" ]
    do :;   done                        &&
    mkfifo  -m a-w,u=rwx "$$.$((_$$))"  &&
    printf  %s "$PWD/$$.$((_$$))"       &&
    exec    >&- >&0                     &&
    case    $1 in
    (+)     shift
            eval "  rm $$.$((_$$))
                    cd - >/dev/null
            $@" < "$$.$((_$$))" &;;
    (-)     shift
            eval "  rm $$.$((_$$))
                    cd - >/dev/null
            $@" >   "$$.$((_$$))"   &;;
    (*) set --
        : "${1:?"USAGE: [-+] [cmd args...]"}"
    esac
}   <&- <>/dev/null

あなたは非常に奇妙なことが起こっていることを見つけることができます$((_$$))。これは、できるだけコマンド環境に介入しないようにする方法です。私はここを維持しようと本当に頑張っています。みんな関数の目的は、プロセスの置き換えと同じことを行うことであるため、可能な環境値は私が作成できるほどプリミティブです。パイプに書き込まれた任意のコマンドを実行します。

cat "$(_p - echo a b c)"

a b c

以下は、ワークフローの簡略化されたバージョンです。

mkfifo pipe                         # make a pipe
printf %s\\n "$PWD/pipe"            # substitute its file name
exec <&- </dev/null >&- >/dev/null  # break cmd sub i/o
eval "rm pipe;$@" >pipe &           # eval rm; args

このevalコマンドはすべての引数を単一のコマンドでラップするため、evalstdout はeval'd コマンドの全グループの標準出力です。これはシェルこれは、単に標準出力に継承する子プロセスではなく、対応するパイプ記述子を所有します。それでシェルはそうしましたopen()。なぜなら私たちがそうしたからです。ブロックする open() >代わりにいいです<>パイプがリーダーを取得するまで、シェルは停止します。

これはrm、他のプロセスがパイプの読み取りファイル記述子を設定するまで実行がないことを意味します。一部のプロセスが読み取り用に開くとき(上記のようにcatrmケーシングが吊り下げられなくなった最初のアクションは、他のアクションを実行する前にパイプが「d」になることです。これはいいえ問題 - パイプラインすでにリーダープロセスとライタープロセスがあります。みんな大丈夫です。

これは少し面倒です。たとえば、

echo "$(_p -)"

/tmp/6023.6023

^それパイプは「d」されませんrmecho読まないでください。だからevalまだ待っています。殺す:

: </tmp/6023.6023

...しかし、殺すのに十分です。

私が使用する用途は次のとおりです。

exec 9<> "$(_p -)"
sed -ue's/sed/mikeserv/' <&9 &
echo hi sed >&9

hi mikeserv

<()ところで、私は同等のものだけを見せてくれましたが、>()こうしてシミュレートできます。

echo hi sed >"$(_p + sed -e's/sed/mikeserv/' '>&2')"

hi mikeserv

その他のパイプライン


これを行うには、私のハッキング機能は必要ありません。プロセスの置き換えは非常に一般的です。何もあなたを止めることはできません維持するパイプが必要なときにすぐに割り当てて廃棄する必要はありません。

(編集者注:このファイルがどこにあるのかわからないので、少し嫌いです。~から- おそらくあなたはより適応力のある人なので、次のことを受け入れることができます)

eval "exec 9<> " <(:)

パイプがあります - それはすべてあなたのものです。クリーンアップは必要ありません。今行ってもいいです。


_pp- へへ


_pp(){  :   "$((_$$=0))"
        _e()    case    ${1:-0} in
                (i|0)   exec >&- 1<>/dev/null;;
                (o|1) ! exec <&-  <>/dev/null;;
                (e|[2-9])
                        exec <&-  <>/dev/null >&- >&0
                        set     "${1#e}"
                        return  "${1:-2}";;
                (*[\<\>]*)
                        eval "
                        exec <&-  <>/dev/null >&- >&0 $1"
                esac
        cd -P   -- "${TMPDIR:-/tmp}"            &&
        while   [ -h "$$.$((_$$+=1))" ]         ||
                [ -e "$$.$((_$$))"    ]
        do :;   done                            && 
        mkfifo  -m a-w,u=rwx   "$$.$((_$$))"    &&
        printf  "%s/%s" "$PWD" "$$.$((_$$))"    &&
        case    $1  in
        (+*)    set \> \< "$@"  ;;
        (-*)    set \< \> "$@"  ;;
        (*)     rm  "$$.$((_$$))"
                set ''  USAGE:  '<-+>[+-[fd][file]]'
                ${1:?"$(printf "\n%s\t%s [cmd...]$@")"};;
        esac    &&
        case    $3  in
        (?|?[ioe0-9])
                _e  "${3#?}"
                eval "exec $1&$?";;
        (?/*)   _e "$1"'"$2"' "${3#?}";;
        (*)     _e "$1"'"$2"' "$OLDPWD/${3#?}"
        esac    &&
        eval "  shift 3
                eval \" rm $$.$((_$$))
                        cd - >/dev/null
        \$@\"   $2$$.$((_$$)) &"
}

_p...だから...ついに私と一緒に始めました。動作することが証明されています。これら[-+]のオプションは何でも取ることができます。ioeオプションの意味std(in|out|err) stdoutコマンドサブルーチンではほとんど役に立ちませんが)または[0-9]設定した記述子または任意のファイル名として解釈されるすべてを参照してください。引数を使用して呼び出すと、+入力が呼び出すコマンドから出る必要があるため、出力ストリームが理解され、引数が-入力として使用されます。

したがって、sed上記の最後の内容は次のように書くことができます。

echo hi sed >"$(_pp +2 sed s/sed/mikeserv/)"

hi mikeserv

おすすめ記事