Ich möchte das machen:
- Führen Sie einen Befehl aus
- Erfassen Sie die Ausgabe
- Wählen Sie eine Zeile
- Wählen Sie eine Spalte dieser Zeile aus
Nehmen wir als Beispiel an, ich möchte den Befehlsnamen von a erhalten $PID
(bitte beachten Sie, dass dies nur ein Beispiel ist. Ich schlage nicht vor, dass dies der einfachste Weg ist, einen Befehlsnamen von einer Prozess-ID zu erhalten - mein eigentliches Problem ist mit ein anderer Befehl, dessen Ausgabeformat ich nicht steuern kann).
Wenn ich renne, ps
bekomme ich:
PID TTY TIME CMD
11383 pts/1 00:00:00 bash
11771 pts/1 00:00:00 ps
Jetzt mache ich ps | egrep 11383
und bekomme
11383 pts/1 00:00:00 bash
Nächster Schritt : ps | egrep 11383 | cut -d" " -f 4
. Ausgabe ist:
<absolutely nothing/>
Das Problem besteht darin, dass cut
die Ausgabe um einzelne Leerzeichen gekürzt wird und beim ps
Hinzufügen einiger Leerzeichen zwischen der 2. und 3. Spalte cut
eine leere Zeichenfolge ausgewählt wird , um die Ähnlichkeit mit einer Tabelle beizubehalten. Natürlich könnte ich gebrauchencut
das 7. und nicht das 4. Feld auswählen, aber wie kann ich wissen, insbesondere wenn die Ausgabe vorher variabel und unbekannt ist.
Antworten:
Eine einfache Möglichkeit besteht darin, einen Durchgang hinzuzufügen
tr
, um wiederholte Feldtrennzeichen herauszudrücken:quelle
tr
es leichter ist alsawk
Ich denke, der einfachste Weg ist zu verwenden awk . Beispiel:
quelle
ps | awk "\$1==$PID{print\$4}"
oder (besser)ps | awk -v"PID=$PID" '$1=PID{print$4}'
. Natürlich könnte man unter Linux einfach machenxargs -0n1 </proc/$PID/cmdline | head -n1
oderreadlink /proc/$PID/exe
, aber trotzdem ...;
in{ print $4; }
erforderlich? Das Entfernen scheint für mich unter Linux keine Auswirkungen zu haben, nur neugierig auf den ZweckBitte beachten Sie, dass mit dieser
tr -s ' '
Option keine einzelnen führenden Leerzeichen entfernt werden. Wenn Ihre Spalte rechtsbündig ist (wie beips
pid) ...Wenn Sie die erste Spalte verwenden, wird für einige dieser Felder eine leere Zeile angezeigt:
Es sei denn, Sie setzen natürlich ein Leerzeichen voran
Für diesen speziellen Fall von PID-Nummern (nicht Namen) gibt es eine Funktion namens
pgrep
:Shell-Funktionen
Im Allgemeinen ist es jedoch immer noch möglich, Shell-Funktionen präzise zu verwenden, da der
read
Befehl eine nette Sache enthält :Der erste zu lesende Parameter
a
wählt die erste Spalte aus, und wenn mehr vorhanden ist, wird alles andere eingegebenb
. Daher benötigen Sie nie mehr Variablen als die Nummer Ihrer Spalte +1 .So,
gibt dann die 3. Spalte aus. Wie in meinem Kommentar angegeben ...
Ein Pipeline-Lesevorgang wird in einer Umgebung ausgeführt, in der keine Variablen an das aufrufende Skript übergeben werden.
Die Array-Lösung
Wir erhalten dann die Antwort von @frayser, bei der die Shell-Variable IFS, die standardmäßig ein Leerzeichen enthält, verwendet wird, um die Zeichenfolge in ein Array aufzuteilen. Es funktioniert jedoch nur in Bash. Dash und Ash unterstützen es nicht. Es fiel mir wirklich schwer, einen String in einer Busybox-Sache in Komponenten aufzuteilen. Es ist einfach genug, eine einzelne Komponente zu erhalten (z. B. mit awk) und diese dann für jeden benötigten Parameter zu wiederholen. Aber dann rufen Sie wiederholt awk in derselben Zeile auf oder verwenden wiederholt einen Leseblock mit Echo in derselben Zeile. Welches ist nicht effizient oder hübsch. So spalten Sie am Ende mit
${name%% *}
und so weiter. Sie sehnen sich nach Python-Kenntnissen, da Shell-Scripting nicht mehr viel Spaß macht, wenn die Hälfte oder mehr der Funktionen, an die Sie gewöhnt sind, nicht mehr vorhanden sind. Aber Sie können davon ausgehen, dass nicht einmal Python auf einem solchen System installiert wäre, und das war es nicht ;-).quelle
echo "$a"
undecho "$c"
obwohl Anführungszeichen um die Variable verwenden .var=$(....... | { read a b c d; echo $c; })
. Das funktioniert nur für eine einzelne (Zeichenfolge), obwohl Sie es in Bash mitar=($var)
Versuchen
quelle
Array-Variablen verwenden
oder
quelle
Ähnlich wie bei der awk-Lösung von brianegge ist hier das Perl-Äquivalent:
-a
Aktiviert den Autosplit-Modus, der das@F
Array mit den Spaltendaten füllt .Verwenden
-F,
Sie diese Option, wenn Ihre Daten durch Kommas und nicht durch Leerzeichen getrennt sind.Feld 3 wird gedruckt, da Perl von 0 statt 1 zu zählen beginnt
quelle
Das Erhalten der richtigen Zeile (Beispiel für Zeile Nr. 6) erfolgt mit Kopf und Schwanz, und das richtige Wort (Wort Nr. 4) kann mit awk erfasst werden:
quelle
awk NR=6 {print $4}
wäre etwas effizienterawk NR==6 {print $4}
* doh *Anstatt all diese Greps und Sachen zu machen, würde ich Ihnen raten, ps-Funktionen zum Ändern des Ausgabeformats zu verwenden.
Sie erhalten die cmmand-Zeile eines Prozesses mit der angegebenen PID und sonst nichts.
Dies ist POSIX-konform und kann daher als tragbar angesehen werden.
quelle
Dein Befehl
verpasst ein
tr -s
, um Leerzeichen zu drücken, wie Entspannen in seiner Antwort erklärt .Möglicherweise möchten Sie jedoch Folgendes verwenden
awk
, da alle diese Aktionen in einem einzigen Befehl ausgeführt werden:Dies druckt die 4. Spalte in den Zeilen, die enthalten
11383
. Wenn Sie möchten, dass dies übereinstimmt,11383
wenn es am Anfang der Zeile erscheint, können Sie sagenps | awk '/^11383/ {print $4}'
.quelle
Bash's
set
analysiert alle Ausgaben in Positionsparameter.Mit dem
set $(free -h)
Befehlecho $7
wird beispielsweise "Mem:" angezeigt.quelle
set $(sar -r 1 1)
;echo "${23}"
awk
ist der beste Weg, um es zu tun.bash
und nichtawk
.