2017-03-13 3 views
2

私は、ルートLDAPレコードを1回だけ取り出して出力をteeにパイプして、各セクションのprettyプリンターを呼び出すLDAPエントリー用のきれいなプリンターを作成しようとしています。プロセス置き換えの誤解を持つティー

私のgroup_entry関数は、特定のLDAP DNのLDIFを返します。詳細は重要ではありませんので、のは、それが常に返すとしましょう:

dn: cn=foo,dc=example,dc=com 
cn: foo 
owner: uid=foo,dc=example,dc=com 
owner: uid=bar,dc=example,dc=com 
member: uid=foo,dc=example,dc=com 
member: uid=baz,dc=example,dc=com 
member: uid=quux,dc=example,dc=com 
custom: abc123 

を私は簡単に「INGのとcutgrepのビットで個別に所有者とメンバーを抽出INGすることができます。これらの二次DNを別のLDAP検索クエリにパイプして、実際の名前を取得することができます。例のために、のは、私はpretty_print機能を持っているとしましょう、それはLDAP上parametrisedさは、私が今述べたことすべてをした、属性名、次にAWKとうまくすべてをフォーマット:

$ group_entry | pretty_print owner 
Owners: 
foo Mr Foo 
bar Dr Bar 

$ group_entry | pretty_print member 
Members: 
foo Mr Foo 
baz Bazzy McBazFace 
quux The Artist Formerly Known as Quux 

これらを個別に正常に動作しますが、

$ group_entry | tee >(pretty_print owner) | pretty_print member 
Members: 
[Sits there waiting for Ctrl+C] 

はもちろん、私はこれが動作するようになっている方法についていくつかの誤解がありますが、それは私をエスケープ:私はそれらを一緒に teeしようとすると、何も起こりません。私は間違って何をしていますか?


完全を期すために、ここに私の完全なスクリプトは、EDITです:

#!/usr/bin/env bash 

set -eu -o pipefail 

LDAPSEARCH="ldapsearch -xLLL" 

group_entry() { 
    local group="$1" 
    ${LDAPSEARCH} "(&(objectClass=posixGroup)(cn=${group}))" 
} 

get_attribute() { 
    local attr="$1" 
    grep "${attr}:" | cut -d" " -f2 
} 

get_names() { 
    # We strip blank lines out of the LDIF entry, then we always have "dn" 
    # followed by "cn" records; we strip off the attribute name and 
    # concatenate those lines, then sort. So we get a sorted list of: 
    # {{distinguished_name}} {{real_name}} 
    xargs -n1 -J% ${LDAPSEARCH} -s base -b % cn \ 
    | grep -v "^$" \ 
    | cut -d" " -f2- \ 
    | paste - - \ 
    | sort 
} 

pretty_print() { 
    local attr="$1" 
    local -A pretty=([member]="Members" [owner]="Owners") 

    get_attribute "${attr}" \ 
    | get_names \ 
    | gawk -F'\t' -v title="${pretty[${attr}]}:" ' 
    BEGIN { print title } 
    { print "-", gensub(/^uid=([^,]+),.*$/, "\\1", "g", $1), "\t", $2 } 
    ' 
} 

# FIXME I don't know why tee with process substitution doesn't work here 
group_entry "$1" | pretty_print owner 
group_entry "$1" | pretty_print member 
+0

あなたの実際のコード+あなたの間違った出力+あなたの予想される出力を共有することができれば、私たちはあなたをより良く助けることができます。 – Inian

+2

もう一つの問題は、 'pretty_print owner'への呼び出しが' tee'と同じ場所から標準出力を継承していることです。これは 'pretty_print member'がいくつかの追加の予期しない入力を得ることを意味します。 – chepner

+2

2つの 'pretty_print'呼び出しが非同期に実行されるので、出力が同じファイルに書き込まれているとインターリーブされる可能性があります。 – chepner

答えて

1

あなたが記述の行動は非常にフォークやexecが別のプログラムだCプログラムで発生する可能性がある状況のように見えます開いているファイル記述子をすべて正しく処理しなくても(シェルとxargsの両方が確実に行うように) p1は標準入力でEOFを観測するのを待っているため終了しませんが、別のプロセスp2がパイプの書き込み終了のファイル記述子を保持しているため、決して実行されません。 p1の標準入力を提供し、p2は、p1が終了するか、または他の処理を実行するのを待っています。

それにも関わらず、バージョン4.2.46で...私はその点で、あなたのパイプラインを持つ、本質的に間違って何も表示されない、と私はこの単純なモデルでハング再現していない...

echo "foo" | tee >(cat) | cat 

bashである。それにもかかわらず、bash(同じものであっても)のバージョンまたはxargsに関連するバグがありますが、それは推測的です。私はあなたのパイプラインがあなたの言うとおりにハングアップするとは思わないが、私は指を指し始める準備ができていない。

いずれにしても、パイプラインがハングしなかったとしても、@chepnerがコメントで指摘したように、必要なセマンティクスはありません。 pretty_print memberは、標準入力にteeの出力を受け取り、の出力とgroup_entryの出力とpretty_print ownerの出力の両方を含みます。ティーが入力以上の二つの方法を多重化することができるので、あなたは、このことによって、一石二鳥あり、:あなたは違った、それを実装することを検討でき

group_entry "$1" | tee >(pretty_print owner) >(pretty_print member) 

をしかし、それは可能性を開いたままその2つのpretty_print実行の出力混ぜ合わされ、またgroup_entry出力にエコーします。おそらくgroup_entryの出力をフィルタリングすることができますが、混在を避けるためには、2つのpretty_printコマンドを順番に実行する必要があります。 teeベースのアプローチでは、teeの出力のいずれかがブロックされた場合、パイプライン全体がストールする可能性があるため、これは問題になります。

解決策の1つは、pretty_printコマンドの1つまたは両方の出力をファイルにリダイレクトすることです。また、両方の出力が標準出力になることが重要な場合は、group_entry出力をキャプチャして、pretty_printのジョブごとに個別にフィードすることもできます。あなたはそれをファイルに取り込むことができますが、それは不要で、ちょっと面倒です。代わりに、このことを考えてみましょう:

entry_lines=$(group_entry "$1") 
pretty_print owner <<<"$entry_lines" 
pretty_print member <<<"$entry_lines" 

(改行を含む)シェル変数にgroup_entryの出力をキャプチャするためにコマンド置換を使用し、各pretty_printプロセスにそれを再生するには、ここの文字列を使用していること。

関連する問題