Piping in Awk-Skripten

Piping in Awk-Skripten

Ich versuche, einen lsWrapper zu schreiben, der awkdie Ausgabe von analysiert ls -lhF. Im Moment habe ich das Programm in zwei Dateien aufgeteilt – my_ls.shund der einzige Zweck von my_ls.awk. besteht darin, die Ausgabe von in my_ls.shumzuleiten . Es sieht so aus:ls -lhFmy_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.awkwü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 getlineFunktion 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 awkauszudrucken, was lsals das letzte Feld angesehen wird, aber awknicht (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 lsFeld 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 , awkum 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 lsin eine temporäre Datei und lassen Sie awkdiese Datei dann verarbeiten. Die unten gezeigte Methode verwendet(2).

Beachten Sie, dass die Ausgabe von lsmöglicherweise unerwartete, nicht einfache Ausgaben in Ihre Richtung senden kann, wie im Fall von link. Daher ist es im Allgemeinen sicherer, finddie 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.

verwandte Informationen