![Piping in Awk-Skripten](https://rvso.com/image/23956/Piping%20in%20Awk-Skripten.png)
Ich versuche, einen ls
Wrapper zu schreiben, der awk
die Ausgabe von analysiert ls -lhF
. Im Moment habe ich das Programm in zwei Dateien aufgeteilt – my_ls.sh
und der einzige Zweck von my_ls.awk
. besteht darin, die Ausgabe von in my_ls.sh
umzuleiten . Es sieht so aus:ls -lhF
my_ls.awk
#!/bin/bash
ls -lhF "$@" | my_ls.awk
Ich habe mich gefragt, ob es eine Möglichkeit gibt, die Ausgabe ls -lhF
über das Awk-Skript selbst zu lesen.
BEARBEITEN:Mein Hauptziel ist es, ein Skript zu schreiben, das den aktuellen Verzeichnisinhalt in Form eines schönen Baums anzeigt. Eine Entwurfsversion my_ls.awk
würde so aussehen:
#!/usr/bin/awk -f
( NF >= 9 ) {
print "|-- [" $5 "] " $9
}
Dasist, wo ich bisher angekommen bin.
Antwort1
Ich schließe mich dem anderen Ratschlag an, dass Sie die Ausgabe von nicht analysieren sollten ls
, daher ist dies ein schlechtes Beispiel. Aber allgemeiner würde ich das awk-Skript direkt in das Shell-Skript einbinden, indem ich es als Argument an übergebe awk
.
#!/bin/bash
ls -lhF "$@" | awk '
( NF >= 9 ) {
print "|-- [" $5 "] " $9
}'
Beachten Sie, dass '
Sie das Zeichen (einfaches Anführungszeichen) in Anführungszeichen setzen müssen, wenn es im awk-Skript enthalten sein muss: Verwenden Sie '\''
(schließendes einfaches Anführungszeichen, wörtliches einfaches Anführungszeichen, öffnendes einfaches Anführungszeichen).
Um das Zitieren zu vermeiden, können Sie einhier Dokumentstattdessen. Aber das ist umständlich, weil Sie die Standardeingabe nicht gleichzeitig verwenden können, um awk und das Skript zu füttern. Sie müssen einen zusätzlichen Dateideskriptor verwenden (sieheWann würden Sie einen zusätzlichen Dateideskriptor verwenden? Dateideskriptoren und Shell-Skripting).
#!/bin/bash
ls -lhF "$@" | awk -f /dev/fd/3 3<<'EOF'
( NF >= 9 ) {
print "|-- [" $5 "] " $9
}
EOF
Innerhalb von awk können Sie mithilfe der getline
Funktion und der Pipe-Konstruktion Eingaben aus einem anderen Befehl lesen. Dies ist zwar nicht die Art und Weise, für die awk in erster Linie konzipiert ist, aber es lässt sich zum Laufen bringen. Sie müssen die Dateinamenargumente für die zugrunde liegende Shell in Anführungszeichen setzen, was sehr fehleranfällig ist. Und da der zu verarbeitende Text nicht aus den erwarteten Quellen stammt (Standardeingabe oder die in der Befehlszeile benannten Dateien), erhalten Sie am Ende den gesamten Code im Block BEGIN
.
#!/usr/bin/awk -f
BEGIN {
command = "ls -lhF"
for (i = 1; i <= ARGC; i++) {
arg = ARGV[i];
gsub("'", "'\\''", arg);
command = command " '" arg "'";
}
ARGC = 0; for (i in ARGV) delete ARGV[i];
while ((command | getline) > 0) {
if (NF >= 9) { print "|-- [" $5 "] " $9 }
}
}
Kurz gesagt: Verwenden Sie eine Shell für das, was sie gut kann (z. B. das Zusammenführen von Befehlen), und awk für das, was es gut kann (z. B. die Textverarbeitung).
Antwort2
Ich bin nicht ganz sicher, was Sie versuchen, aber ein Problem, das auftreten kann, besteht darin, das awk
auszudrucken, was ls
als das letzte Feld angesehen wird, aber awk
nicht (aufgrund der Standardanalyse). zB.
-rw-r--r-- | 433k | filename-with-no-spaces
-rw-r--r-- | 1k | link containing spaces -> /home/user/filename-with-no-spaces
Irgendwie müssen Sie das letzte ls
Feld isolieren. Der unten gewählte Ansatz besteht darin, die Länge aller vorhergehenden Felder und Trennzeichen zu ermitteln. Der Rest ist das Dateinamenfeld (plus andere Informationen, wie das Ziel eines Links).
Das folgende Skript bestimmt die maximale Breite der Variable-widthGrößeFeld (wird für die Ausgabeformatierung benötigt). Es gibt mehrere Möglichkeiten, diese Breite zu erhalten, z. B.(1)Verwenden Sie es , awk
um jede Ausgabezeile ls
in der Hauptschleife zu verarbeiten und jede Zeile einem Array zur nachfolgenden END{ }
Verarbeitung hinzuzufügen. oder(2) Schreiben Sie die Ausgabe ls
in eine temporäre Datei und lassen Sie awk
diese Datei dann verarbeiten. Die unten gezeigte Methode verwendet(2).
Beachten Sie, dass die Ausgabe von ls
möglicherweise unerwartete, nicht einfache Ausgaben in Ihre Richtung senden kann, wie im Fall von link
. Daher ist es im Allgemeinen sicherer, find
die Ausgabe zu verwenden und anzupassen, damit sie Ihren Analyseanforderungen besser entspricht.
f=7 # the number of (multi-space) delimiters before the start of the filename
myls="$(mktemp)" # a temp file to hold output from `ls`
w=$(ls --color=always -lFHk ~/ |tee "$myls" |awk '{print $5}' |wc -L) # max width of size field
h=k # size unit
awk --re-interval -v"f=$f" -v"w=$w" -v"h=$h" '
NF >= f {
regex = "^([^ ]+ +){"f"}"
match( $0, regex ) # find start of name field
printf( "%s | %"w"s%s | %s\n", $1, $5, h, substr( $0, RLENGTH ))
}' "$myls"
rm "$myls"
Antwort3
Ich empfehle, das Rad nicht neu zu erfinden und stattdessen zu verwenden tree
, wodurch die Dateien/Ordner eines Verzeichnisses und die Dateien/Ordner der Unterverzeichnisse angezeigt werden:
tree(1) - Linux-Manpage
Name
Baum - listet den Inhalt von Verzeichnissen in einem baumartigen Format auf.
Zusammenfassung
Baum [-adfghilnopqrstuvxACDFNS] [-L Ebene [-R]] [-H BasisHREF] [-T Titel] [-o Dateiname] [--nolinks] [-P Muster] [-I Muster] [--inodes] [--device] [--noreport] [--dirsfirst] [--version] [--help] [--filelimit #] [Verzeichnis ...]
Beschreibung
Tree ist ein rekursives Verzeichnisauflistungsprogramm, das eine tief eingerückte Auflistung von Dateien erstellt. Farbe wird wie bei dircolors unterstützt, wenn die Umgebungsvariable LS_COLORS gesetzt ist, die Ausgabe an ein TTY erfolgt und das Flag -C verwendet wird. Ohne Argumente listet tree die Dateien im aktuellen Verzeichnis auf. Wenn Verzeichnisargumente angegeben werden, listet tree nacheinander alle Dateien und/oder Verzeichnisse auf, die in den angegebenen Verzeichnissen gefunden wurden. Nach Abschluss der Auflistung aller gefundenen Dateien/Verzeichnisse gibt tree die Gesamtzahl der aufgelisteten Dateien und/oder Verzeichnisse zurück.
Wenn ein symbolischer Link gefunden wird, wird standardmäßig der Pfad, auf den der symbolische Link verweist, nach dem Namen des Links im folgenden Format gedruckt:
Name -> realer Pfad
Wenn die Option „-l“ angegeben ist und der symbolische Link auf ein tatsächliches Verzeichnis verweist, folgt tree dem Pfad des symbolischen Links, als wäre es ein echtes Verzeichnis.