2017-03-13 5 views
2

Ich versuche, einen hübschen Drucker für LDAP-Einträge zu schreiben, die nur den Stamm LDAP-Datensatz einmal holt und dann die Ausgabe in tee, die den hübschen Drucker für jeden Abschnitt aufruft.T-Stück mit Prozess Substitution Missverständnis

Zur Veranschaulichung sagen meine group_entry Funktion gibt die LDIF eines bestimmten LDAP-DN zurück. Die Einzelheiten sind nicht wichtig, also lassen Sie uns sagen, dass es immer wieder:

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 

ich einfach an die Eigentümer und die Mitglieder separat mit etwas grep ‚ing und cut‘ ing extrahieren kann. Ich kann diese sekundären DNs dann in eine andere LDAP-Suchabfrage leiten, um ihre echten Namen zu erhalten. Aus Gründen der Beispiel sagen wir, ich habe eine pretty_print Funktion, die auf dem LDAP-parametrisiert wird Attributnamen, die alle tut, die ich gerade erwähnt und formatiert dann alles schön mit 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 

Diese funktionieren einzeln in Ordnung, aber wenn ich versuche, sie zusammen zu tee, passiert nichts:

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

Offensichtlich ich einige Missverständnisse darüber, wie das funktionieren soll, aber es entgeht mir. Was mache ich falsch?


EDIT Der Vollständigkeit halber, hier ist mein ganzes Skript:

#!/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

Wenn Sie den tatsächlichen Code teilen können, den Sie versuchen + Ihre falsche Ausgabe + Ihre erwartete Ausgabe, wird es uns einfach sein, Ihnen besser zu helfen. – Inian

+2

Ein weiteres Problem ist, dass der Aufruf von 'pretty_print owner' seine Standardausgabe von der gleichen Stelle wie' tee' erbt, was bedeutet, dass 'pretty_print member' einige zusätzliche unerwartete Eingaben erhält. – chepner

+2

Es gibt auch das Problem, dass die beiden Aufrufe von 'pretty_print' asynchron ausgeführt werden, sodass ihre Ausgabe wahrscheinlich verschachtelt wird, wenn sie in dieselbe Datei schreiben. – chepner

Antwort

1

Das Verhalten, das Sie eine Situation sieht beschreiben sehr ähnlich, die ein anderes Programm in einem C-Programm, das Gabeln und Exec auftreten können (wie die Shell und die Xargs beide sicherlich tun), ohne alle offenen Dateideskriptoren richtig zu handhaben. Sie können in einer Situation bleiben, in der ein Prozess p1 nicht beendet wird, weil es auf EOF auf seiner Standardeingabe wartet, aber es nie tun wird, weil ein anderer Prozess p2 einen geöffneten Dateideskriptor für das Schreibende der Pipe enthält das liefert p1 's Standardeingabe, und p2 wartet selbst auf p1, um zu beenden oder irgendeine andere Tätigkeit durchzuführen.

Aber ich sehe nichts von Natur aus falsch mit Ihrer Pipeline in dieser Hinsicht, und ich nicht reproduziere die mit diesem einfacheren Modell hängen ...

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

... in der Version 4.2.46 von bash. Es kann sein, dass es in Ihrer Version von bash (auch wenn es die gleiche ist), aber in xargs, ein verwandter Bug ist, aber das ist spekulativ. Ich denke nicht, dass Ihre Pipeline hängen sollte, wie Sie es sagen, aber ich bin nicht bereit, Finger zu zeigen.

In jedem Fall, auch wenn Ihre Pipeline nicht hängen blieb, hat es nicht die gewünschte Semantik, wie @chepner in Kommentaren darauf hingewiesen. Die pretty_print member wird die Ausgabe von tee auf seinem Standard-Eingang erhalten, und das wird sowohl die Ausgabe von group_entry und die Ausgabe von pretty_print owner enthalten.Man könnte es für unterschiedlich Umsetzung: Da T-Shirt-Eingang mehr als zwei Möglichkeiten multiplexen kann, können Sie diese zwei Fliegen mit einer Klappe schlagen können, indem Sie:

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

Aber das lässt die Möglichkeit offen, dass der Ausgang der beiden pretty_print Hinrichtungen wird vermischt und gibt auch den group_entry Ausgang aus. Sie könnten den group_entry Ausgang herausfiltern, aber um das Vermischen zu vermeiden, müssen Sie sicherstellen, dass die beiden pretty_print Befehle sequenziell ausgeführt werden. Dies stellt ein Problem für einen tee -basierten Ansatz dar, da, wenn irgendwelche Ausgaben von tee blockieren, die gesamte Pipeline zum Stillstand kommen kann.

Eine Lösung wäre, die Ausgabe eines oder beider pretty_print Befehle in eine Datei umzuleiten. Alternativ, wenn es wichtig ist, dass beide Ausgänge auf stdout gehen, dann sehe ich keine gute Alternative, aber um die group_entry Ausgabe zu erfassen und sie separat jedem pretty_print Job zuzuführen. Sie könnten es in einer Datei erfassen, aber das ist unnötig und ein bisschen chaotisch. Betrachten Sie stattdessen:

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

, die Befehlssubstitutions verwendet die Ausgabe von group_entry in einer Shell-Variablen (einschließlich newlines) zu erfassen, und verwendet eine Zeichenkette, die es hier zu wiederholen in jeden pretty_print Prozess.