2017-02-28 2 views
0

Ich arbeite an einem Skript, das die Daten analysieren muss, die von einem ps-Befehl zurückgegeben werden. Auf Redhat/Centos weiß ich, dass es einfach ist, das Spaltentrennzeichen zu spezifizieren, aber mit dem BSD version of PS ist es nicht so einfach.PS-Spaltenbegrenzer auf OSX (BSD) setzen

Ich weiß, es wäre möglich, awk, sed oder tr zu verwenden Leerzeichen zu ersetzen mit dem, was Charakter, aber sagen wir mal das Format args oder comm irgendwo in der Mitte hat, wäre der Ausgang sein:

$ ps -o pid,ppid,args,user | head 
    PID PPID ARGS                USER 
60140 494 /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp jdoe 
60144 60141 -bash               jdoe 
55574 494 /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp jdoe 
55576 55575 -bash               jdoe 
20710 494 /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp jdoe 
20712 20711 -bash               jdoe 
66703 494 /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp jdoe 
66707 66704 -bash               jdoe 
66881 494 /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp jdoe 

Wie Sie sehen können, können die Daten in der Spalte args Leerzeichen enthalten, wodurch das Ganze ausgeschaltet wird.

Was wirklich irritierend ist, fand ich tatsächlich eine Lösung, die gut zu funktionieren schien, ohne etwas wie args am Ende der Ausgabe zu tun, aber ich kann mich nicht an die Lösung erinnern, oder finde es wieder.

Ich dachte, dass es vielleicht möglich wäre, die Spaltenüberschriftzeile zu verwenden, um die Breite der Spalten zu bestimmen, da die Überschriften mit den Spaltendaten übereinstimmen, aber ich bin mir sicher, dass es eine einfachere Lösung gibt.

Jede Hilfe wäre willkommen. Vielen Dank!

+1

Warum gerade 'Sie können nicht als letzte Spalte args' und Lesen von Daten mit' Awk'? Kannst du es so benutzen? – Inian

+0

Das einzige idiotensichere Trennzeichen wäre ein Nullzeichen. – chepner

+0

Was möchten Sie eigentlich mit diesen Daten machen? Was ist dein Endspiel? Lassen Sie uns sehen, ob wir herausfinden können, wie Sie Ihr Ziel erreichen können, anstatt Sie einfach abzuschicken, was der falsche Weg sein könnte. – ghoti

Antwort

0
ps -o pid,ppid,args,user \ 
awk -v Rpl='_' ' 
    # line but the header 
    NR > 1 { 
     p = $1 
     P = $2 
     u = $NF 
     A = $0 
     sub("^[[:blank:]*" p "[[:blank:]*" P "[[:blank:]*", "", A) 
     sub("[[:blank:]*" u "[[:blank:]*$", "", A) 
     gsub(" ", Rpl, A) 

     # recreate the line 
     $0 = sprintf("%d\t%d\t%s\t%s\n", p, P, A, u) 
     } 

    # print the line 
    7 
    ' 

Hinweise:

  • Ich benutze zusätzlichen Code als nötig zu zeigen, wo und wie die Informationen zu nehmen, p, P und U können direkt $ 1, sein werden ...
  • ich neu Die Linie kann direkt gedruckt werden. Es ist in dem Fall, dass Sie die Zeile oder den Inhalt behandeln und expliziter sein möchten.
  • 7 ist ein nicht 0 (privat Witz, 1 genügt und nicht verwirrend), die als Standardaktion hat die aktuelle Zeile
  • Rpl Inhalt (zugeordnet außerhalb awk batch Interaktion zu ermöglichen) zu drucken, ist das Muster, das die ersetzen Leerzeichen könnte alles sein (leer ist auch verfügbar).
  • Ich benutze \t als neue Trennzeichen, könnte alles andere sein.
  • anpassen, wenn andere Feld der ps verwendet werden, aber nicht funktionieren, wenn mehrere potentielle Raum innerhalb haben.
+0

Einige der Werte in den 'args' Spalten Räume haben, die diese miteinander verbindet. Weißt du, wie ich das beheben kann? Vielleicht in der 'args' Spalte ersetzen Räume mit so etwas wie' '||, dann, wenn sie ausgegeben wird, ersetzen' || 'mit einem Leerzeichen. Aber ansonsten ist das definitiv besser als das, was ich hatte. – Justin

+0

Edit: Ich habe nicht vollständig in die Logik vor dem Posten der oben genannten. Aber wenn die Säulen bewegt werden, funktioniert das nicht, richtig? Ich hätte das schreiben sollen, aber ich muss die Spalten verschieben können. – Justin

+0

die einzigen constrain i zu definieren, wo der Abstand Feld ist, und wenn es nur 1 ist, könnte man anstelle des anderen wie hier übernehmen. Das einfachste, wenn möglich, ist das Feld so zu bestellen, dass man den Abstand (ARGS hier) am letzten Platz hat, so dass andere sehr leicht zu fangen und zu filtern sind. – NeronLeVelu

-1

PS-Dienstprogramm auf neuesten FreeBSD11 hat --libxo Option, die verwendet werden können, die Ausgabe von ps in XML Format, Text, json usw. Obwohl diese Option nicht in ps Dienstprogramm zur Verfügung stehen wird, die von früheren bsd kommt (dh openbsd 6 oder freebsd weniger als 11).

Wenn --libxo verfügbar ist eine Abhilfe könnte ps --libxo json zu verwenden und dann jq verwenden, um die Werte abzurufen, die Sie benötigen, oder ein anderes Werkzeug wie sed verwenden.

diesen Test Siehe:

$ ps --libxo json -o pid,args |tr '}' '\n' |sed 's/["{:]//g;s/arguments//g;s/pid//g;s/^,//g' 

804,-csh (csh) 
813,dbus-launch --sh-syntax --exit-with-session 
816,xinit /usr/local/etc/xdg/xfce4/xinitrc 
817,X 0 (Xorg) 
819,sh /usr/local/etc/xdg/xfce4/xinitrc 
825,xfce4-session 
..................................................... 

Sie können cut die formatierten stram und Extrakt Felder basierend auf Komma als Trennzeichen weiter (i.e Rohr über Ausgang |cut -d, -f2 gibt Ihnen nur die Argumente

Natürlich wenn Sie wissen, wie man mit jq arbeitet, brauchen Sie nicht alle diese Rohre und seds, Sie können die Felder direkt vom json Strom extrahieren.

Sie können auch in man xo_parse_args für weitere Optionen über die Option --libxo von PS suchen.

+0

@Justin Hat das funktioniert? –

+0

Nein, im auf OSX, und Theres keine '--libxo' Option, zumindest nicht in der Version habe ich. https://gist.github.com/jhyland87/6ff0266abc9a9b57690ab28dfc18c180 – Justin

+0

@Justin - FYI, OSX 'ps' Befehl basiert auf [der' ps' Befehl von FreeBSD 6.0] (https://www.freebsd.org/cgi/ man.cgi? query = ps & manpath = FreeBSD + 6.0-RELEASE) (veröffentlicht im Jahr 2005), welches die Option '--libxo' nicht enthält. Diese Option [wurde tatsächlich zu FreeBSD 11 hinzugefügt] (https://www.freebsd.org/cgi/man.cgi?query=ps&manpath=FreeBSD+11.0-RELEASE), die 2016 veröffentlicht wurde. – ghoti

0

Nun, da Ihre bsd ps die Option --libxo nicht unterstützt, wie in meiner vorherigen Antwort empfohlen, könnten Sie immer klassische Bash-Ansatz verwenden, indem Sie die Abstände Args am Ende.

Sie können dann eine Schleife verwenden, um die gesamte PS-Ausgabe in einem Array zu lesen, und dann können Sie die Aufgaben in beliebiger Reihenfolge Sie durch Einstellen des Drucks der entsprechenden Array-Elemente wollen drucken.

Aber für „Parsen“ Sie Abstand args am Ende halten müssen. Zum Drucken drucken Sie das Array einfach in anderer Reihenfolge.

diesen Test Siehe, und die Räume in Feldelement No7,11,15 dagegen:

$ while read -r pid ppid user args;do \ 
psdata+=("$pid" "$ppid" "$user" "$args"); \ 
done< <(ps -o pid,ppid,user,args) 

$ declare -p psdata #let's ask bash to print the array for us 
declare -a psdata=([0]="PID" [1]="PPID" [2]="USER" [3]="COMMAND" [4]="769" \ 
[5]="1" [6]="root" [7]="/usr/libexec/getty Pc ttyv0" [8]="770" [9]="1" \ 
[10]="root" [11]="/usr/libexec/getty Pc ttyv1" [12]="771" [13]="1" [14]="root" \ 
[15]="/usr/libexec/getty Pc ttyv2" [16]="772" [17]="1" [18]="root" \ 
# more items here