Wie extrahieren Sie alle Befehlszusammenfassungen korrekt aus den Manpages in /usr/share/man/man1?

Wie extrahieren Sie alle Befehlszusammenfassungen korrekt aus den Manpages in /usr/share/man/man1?

Ich versuche alles zu extrahierenBefehlszusammenfassungenaus den Manpages bei /usr/share/man/man1Verwendung von:

#!/usr/bin/env bash
## synopses - extract all synopses in /usr/share/man/man1

cd /usr/share/man/man1
for i in *.gz; do
    echo "$i:" | sed -E "s/.1.gz|.gz//g"
    man "./$i" | sed -n '/^SYNOPSIS/,/^[A-Z][A-Z][A-Z]/p' | sed -e '1d; $d' | tr -s [:space:]
done

...der bereitstelltmancheErfolgsmaßstab - ich erhalte eine vollständige Ausgabe für Befehle vonAZuz. Aber ich bekomme auch viele Fehler aufstderrunter Verwendung von for i in ./*.gz; do man "$i"sowohlfor i in *.gz; do man "./$i"wie ich in eine Datei ausgebe( synopses > file) 1 :

<standard input>:27: expected `;' after scale-indicator (got `o')
<standard input>:29: expected `;' after scale-indicator (got `o')
<standard input>:283: name expected (got `\{'): treated as missing
<standard input>:674: warning: macro `as',' not defined (possibly missing space after `as')
<standard input>:174: name expected (got `\{'): treated as missing
<standard input>:161: warning [p 1, 5.5i]: can't break line
<standard input>:594: warning [p 5, 3.8i, div `an-div', 0.0i]: can't break line
<standard input>:569: warning [p 6, 0.0i]: can't break line
<standard input>:147: warning [p 1, 1.8i]: can't break line
<standard input>:205: warning [p 2, 0.2i]: can't break line
<standard input>:525: warning [p 5, 4.5i]: can't break line
<standard input>:157: warning [p 1, 4.8i]: can't break line
<standard input>:351: warning [p 3, 1.8i, div `an-div', 0.0i]: can't break line
<standard input>:147: a space character is not allowed in an escape name
man: can't open man1/zshmisc.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshexpn.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshparam.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshoptions.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshbuiltins.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshzle.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshcompwid.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshcompsys.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshcompctl.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshmodules.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshcalsys.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshtcpsys.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshzftpsys.1: No such file or directory
man: -:423: warning: failed .so request
man: can't open man1/zshcontrib.1: No such file or directory
man: -:423: warning: failed .so request
<standard input>:423: can't open `man1/zshmisc.1': No such file or directory
<standard input>:424: can't open `man1/zshexpn.1': No such file or directory
<standard input>:425: can't open `man1/zshparam.1': No such file or directory
<standard input>:426: can't open `man1/zshoptions.1': No such file or directory
<standard input>:427: can't open `man1/zshbuiltins.1': No such file or directory
<standard input>:428: can't open `man1/zshzle.1': No such file or directory
<standard input>:429: can't open `man1/zshcompwid.1': No such file or directory
<standard input>:430: can't open `man1/zshcompsys.1': No such file or directory
<standard input>:431: can't open `man1/zshcompctl.1': No such file or directory
<standard input>:432: can't open `man1/zshmodules.1': No such file or directory
<standard input>:433: can't open `man1/zshcalsys.1': No such file or directory
<standard input>:434: can't open `man1/zshtcpsys.1': No such file or directory
<standard input>:435: can't open `man1/zshzftpsys.1': No such file or directory
<standard input>:436: can't open `man1/zshcontrib.1': No such file or directory

Was <standard input>bedeuten diese Fehler (ist etwas entgangen?) und warum werden maneinige Dateien am Ende nicht gefunden? Wie kann ich das robuster/effizienter machen?


1. Es scheint, dass die Fehler aufstderrsind gleich, egal welche Implementierung/Lösung ich für dieselben Daten verwende. Das ist auffällig.

Antwort1

Man kann nicht einfach weglaufenman foo.gzEs sieht aus wie dudürfenlaufen man foo.1.gz, aber die Verwendung -lscheint sauberer zu sein. Von man man:

   -l, --local-file
          Activate `local' mode.  Format and display  local  manual  files
          instead  of  searching  through  the system's manual collection.
          Each manual page argument will be interpreted as an nroff source
          file in the correct format.  No cat file is produced.  If '-' is
          listed as one of the arguments, input will be taken from  stdin.
          When  this  option  is  not used, and man fails to find the page
          required, before displaying the error message,  it  attempts  to
          act as if this option was supplied, using the name as a filename
          and looking for an exact match.

Ihr Skript sollte also etwa so aussehen:

#!/usr/bin/env bash
## synopses - extract all synopses in /usr/share/man/man1

## No need to cd into the directory, you can just use globs     
for i in /usr/share/man/man1/ajc*.gz; do
    ## This will print the name of the command.      
    basename "${i//.1.gz}"
    man -l "$i"  | 
       awk '/^SYNOPSIS/{a=1; getline}
            (/^[a-zA-z0-9_]/ && a==1){a=0} 
            (a==1 && /./){print}' | tr -s [:space:]

done

Der awkvon mir angegebene Befehl funktioniert besser als Ihr Ansatz (testen Sie ihn man ajcbeispielsweise an) und funktioniert jetzt auch bei mehrzeiligen Zusammenfassungen. Die meisten der angezeigten Fehler sind irrelevant, andere waren auf die Art und Weise zurückzuführen, wie Sie mit Dateinamen umgegangen sind. Lassen Sie mich wissen, ob dieser besser funktioniert.

Antwort2

Die aufgetretenen Fehler werden alle hier behandelt:

man man

MANWIDTH- Wenn $MANWIDTHgesetzt ist, wird sein Wert als Zeilenlänge verwendet, für die Handbuchseiten formatiert werden sollen. Wenn es nicht gesetzt ist, werden Handbuchseiten mit einer Zeilenlänge formatiert, die dem aktuellen Terminal entspricht (mit ioctl(2), falls verfügbar, dem Wert von $COLUMNSoder mit 80 Zeichen, falls keines von beiden verfügbar ist). Handbuchseiten werden nur gespeichert, wenn die Standardformatierung verwendet werden kann, d. h. wenn die Zeilenlänge des Terminals zwischen 66 und 80 Zeichen liegt.

MAN_KEEP_FORMATTING- Wenn die Ausgabe nicht an ein Terminal geleitet wird (z. B. an eine Datei oder eine Pipe), werden Formatierungszeichen normalerweise verworfen, um das Lesen des Ergebnisses ohne Spezialwerkzeuge zu erleichtern. Wenn jedoch $MAN_KEEP_FORMATTINGauf einen beliebigen nicht leeren Wert gesetzt ist, werden diese Formatierungszeichen beibehalten. Dies kann für Wrapper um man nützlich sein, die Formatierungszeichen interpretieren können.

MAN_KEEP_STDERR- Wenn die Ausgabe an ein Terminal (normalerweise an einen Pager) geleitet wird, wird normalerweise jede Fehlerausgabe des Befehls, der zum Erstellen formatierter Versionen von Handbuchseiten verwendet wird, verworfen, um Störungen der Anzeige des Pagers zu vermeiden. Programme wie grofferzeugen oft relativ geringfügige Fehlermeldungen über typografische Probleme wie schlechte Ausrichtung, die unansehnlich und im Allgemeinen verwirrend sind, wenn sie zusammen mit der Handbuchseite angezeigt werden. Einige Benutzer möchten sie jedoch trotzdem sehen, daher $MAN_KEEP_STDERRwird die Fehlerausgabe wie üblich angezeigt, wenn auf einen beliebigen nicht leeren Wert gesetzt ist.

Und nun dazu, wie Sie das andere tun könnten:

Ich denke, das hier macht, was Sie wollen:

for f in /usr/share/man/man1/*gz ; do
    man -P "sed -ne '1,/^[Nn]/d;/^ /{H;b}
    /^[Ss]..[Yy]..[Nn]/{g;:n
    N;/\n\(\n\)[^ ].*/!bn;s//\1/
    s/.\x08//g;s/\(\n\)  */\1/g;
    w /dev/stderr' -ne '};/./q'" -l "$f"
done 2>~/file

Es gibt an, dass es sedsich um die Zeile handelt PAGER, und gibt dann nur die folgende Zeile ausNAMEund die folgendenZUSAMMENFASSUNGbis es auf eine andere Zeile trifft, die mit etwas anderem als a beginnt <space>. Es drucktNichtswenn die erste Zeile, die nicht damit beginnt, <space>folgtNAMEstimmt nicht mit begin überein [Ss][Yy][Nn]. In jedem Fall wird das Lesen der Datei in der zweiten Zeile beendet, die nachNAMEdas nicht mit beginnt <space>. Es löscht führende <spaces>und alle \bAckslashs aus der Ausgabe.

Ich habe es forgerade in einer Schleife ausgeführt und es hat manin nur einer Minute meine gesamte Bibliothek durchlaufen.

manpasst seine Ausgabe an, je nachdem, ob es in ein Terminal oder eine Pipe/Datei schreibt. Wenn Sie ihm also sagen, dass er das tun soll, verzichtet er ganz auf den PAGER. Das war unerwartet. Aber ich habe es ausgetrickst und die wRite-Funktion von sed verwendet, um in >&2 zu schreiben und das umzuleiten, also hat es nichts gemerkt.

Eine Anmerkung jedoch: Es ist vielleicht die bessere Vorgehensweise von @terdon. Sie können dies zwar einfacher anpassen, da Sie eine sedpro Datei erhalten, und die Formatierung ist etwas besser, da sie nicht versucht, auf die Breite eines Terminals zu passen, diese \Backslashes werden anscheinend jedoch mannicht in ein geschrieben |pipe.

verwandte Informationen