Grep: Unerwartete Ergebnisse bei der Suche nach Wörtern in der Überschrift der Manpage

19

Ich habe komisches Verhalten, wenn ich versuche, eine Manpage unter macOS zu lesen. In der Bash-Manpage kommt beispielsweise eindeutig die Zeichenfolge vor NAME:

$ man bash | head -5 | tail -1
NAME

Und wenn ich greife name, bekomme ich Ergebnisse, aber wenn ich greife, NAMEtue ich das nicht:

$ man bash | grep 'NAME'
$ man bash | grep NAME

Ich habe andere Großbuchstaben ausprobiert, von denen ich weiß, dass sie vorhanden sind, und habe nach Ergebnissen SHELLnichts gesucht, wohingegen nach BASHErgebnissen gesucht wurde .

Was ist hier los?

Update : Danke für alle Antworten! Ich dachte, es lohnt sich, den Kontext hinzuzufügen, in dem ich darauf gestoßen bin. Ich wollte eine Bash-Funktion zum manUmbrechen schreiben und in Fällen, in denen ich versucht habe, die Manpage nach einer eingebauten Shell zu durchsuchen, zum entsprechenden Abschnitt der Bash-Manpage springen. Es könnte einen besseren Weg geben, aber hier ist, was ich aktuell habe:

man () {
  case "$(type -t "$1")" in
    builtin)
      local pattern="^ *$1"

      if bashdoc_match "$pattern \+[-[]"; then
        command man bash | less --pattern="$pattern +[-[]"
      elif bashdoc_match "$pattern\b"; then
        command man bash | less --pattern="$pattern[[:>:]]"
      else
        command man bash
      fi
      ;;
    keyword)
      command man bash | less --hilite-search --pattern='^SHELL GRAMMAR$'
      ;;
    *)
      command man "$@"
      ;;
  esac
}

bashdoc_match() {
  command man bash | col -b | grep -l "$1" > /dev/null
}
ivan
quelle
Welches Betriebssystem verwenden Sie? Ich bin sicher, dass die akzeptierte Antwort korrekt ist, aber IO konnte dies auf meiner Arch Linux-Box nicht reproduzieren. man bash | grep NAMEfunktioniert wie erwartet.
Terdon
@terdon Ich bin auf MacOS. Ich bekomme dieses Verhalten mit Bash 3.2 und 4.4.5
ivan
Übrigens: Wenn Sie ein eingebautes Gerät erkennen, können Sie einfach den helpBefehl bash verwenden , um dessen Informationen abzurufen .
Joe
@ Joe Das Problem ist, dass ich oft finde, dass die helpErgebnisse zu viel auslassen . Schauen Sie sich zum Beispiel help completeden completeAbschnitt an man bash.
Iwan

Antworten:

33

Wenn Sie | sed -n ldiesem tailBefehl ein hinzufügen , um nicht druckbare Zeichen anzuzeigen, wird wahrscheinlich Folgendes angezeigt:

N\bNA\bAM\bME\bE

Das heißt, jedes Zeichen wird als XRücktaste geschrieben X. Auf modernen Terminals wird das Zeichen ohne Unterschied über sich selbst geschrieben (da Backspace aka BS aka \baka ^Hdas Zeichen ist, das den Cursor eine Spalte nach links bewegt). Aber in alten Teleschreibmaschinen würde dies dazu führen, dass das Zeichen fett dargestellt wird, da es doppelt so viel Tinte erhält.

Trotzdem verstehen Pager wie more/ less, dass dieses Format fett bedeutet, und das ist es auch, was roffzur Ausgabe von fettem Text verwendet wird.

Einige Implementierungen rufen roffdiese Sequenzen so auf, dass sie nicht verwendet werden (oder rufen col -b -p -xsie intern auf, um sie wie im Fall der man-dbImplementierung zu entfernen (es sei denn, die MAN_KEEP_FORMATTINGUmgebungsvariable ist festgelegt)), und rufen keinen Pager auf, wenn sie die Ausgabe erkennen Ich gehe nicht zu einem Terminal ( man bash | grep NAMEwürde dort also funktionieren), aber nicht zu deinem.

Sie können col -bdiese Sequenzen entfernen (es gibt auch andere Typen ( _BS X) zum Unterstreichen).

Bei Systemen, die GNU verwenden roff(wie GNU oder FreeBSD), können Sie verhindern, dass diese Sequenzen an erster Stelle verwendet werden, indem Sie sicherstellen, dass die -c -b -uOptionen an übergeben werden grotty, beispielsweise indem Sie sicherstellen, dass die -P-cbuOptionen an übergeben werden groff.

Zum Beispiel durch Erstellen eines Wrapper-Skripts mit dem Namen „ groffEnthält:

#! /bin/sh -
exec /usr/bin/groff -P-cbu "$@"

Das hast du vor / usr / bin / groff gesetzt $PATH.

Mit macOS ' man(auch mit GNU roff) können Sie ein man-no-overstrike.confmit:

NROFF /usr/bin/groff -mandoc -Tutf8 -P-cbu

Und ruf an manals:

man -C man-no-overstrike.conf bash | grep NAME

roffWenn Sie bei GNU die GROFF_SGRUmgebungsvariable festlegen (oder die GROFF_NO_SGRVariable nicht festlegen , je nachdem, wie die Standardeinstellungen zum Zeitpunkt der Kompilierung festgelegt wurden), werden stattdessen grotty(sofern diese -cOption nicht übergeben wird ) Escape-Sequenzen für ANSI SGR-Terminals verwendet dieser BS-Tricks für Zeichenattribute. lessVerstehe sie, wenn sie mit der -ROption aufgerufen werden .

Der Benutzer von FreeBSD ruft grottymit der -cOption auf, es sei denn, Sie fordern Farben an, indem Sie die Variable MANCOLOR setzen (in diesem Fall -cwird die Verwendung von ANSI SGR-Escape-Sequenzen dort nicht übernommen grottyund grottyauf die Standardeinstellung zurückgesetzt).

MANCOLOR=1 man bash | grep NAME

wird dort arbeiten.

Unter Debian ist GROFF_SGR nicht die Standardeinstellung. Wenn Sie tun:

GROFF_SGR=1 man bash | grep NAME

Da es sich manbei stdout jedoch nicht um ein Terminal handelt, muss auch eine GROFF_NO_SGRVariable an übergeben werden grotty(ich nehme an, damit können col -bpxdie BS-Sequenzen entfernt werden, da colnicht bekannt ist, wie die SGR-Sequenzen entfernt werden, obwohl dies immer noch der Fall ist tut es mit MAN_KEEP_FORMATTING) was unser überschreibt GROFF_SGR. Sie können stattdessen Folgendes tun:

GROFF_SGR=1 MANPAGER='grep NAME' man bash

(in einem Terminal), um die SGR-Escape-Sequenzen zu erhalten.

Dieses Mal werden Sie feststellen, dass einige dieser NAMEN auf dem Terminal (und in einem less -RPager) fett gedruckt sind. Wenn Sie die Ausgabe an sed -n l( MANPAGER='sed -n /NAME/l') weiterleiten, wird Folgendes angezeigt:

\033[1mNAME\033[0m$

Wo \e[1mist die Reihenfolge, in der in ANSI-kompatiblen Terminals Fettdruck aktiviert werden soll, und \e[0mdie Reihenfolge, in der alle SGR-Attribute auf die Standardwerte zurückgesetzt werden sollen?

Dieser Text grep NAMEfunktioniert so wie der Text enthält NAME, aber Sie könnten trotzdem Probleme haben, wenn Sie nach Text suchen, bei dem nur Teile davon fett / unterstrichen sind ...

Stéphane Chazelas
quelle
2
Wow, es ist ziemlich interessant, das Erbe des physischen Teletyps dort zu sehen. Doppelt so viel Tinte => fett. Macht absolut Sinn
ivan
1
Ich liebe sed -n lals Ersatz für od.
Tom Hale
13

Wenn Sie sich eine Handbuchseite ansehen, werden Sie feststellen, dass die Überschriften fett gedruckt sind. Dies wird erreicht, indem sie mit Steuerzeichen formatiert werden. Um grepIhren Wünschen entsprechen zu können, müssen diese entfernt werden.

Das colDienstprogramm kann dazu verwendet werden:

$ man bash | col -b | grep 'NAME'

Die -bOption hat die folgende Beschreibung unter OpenBSD :

Geben Sie keine Leerzeichen aus, sondern drucken Sie nur das letzte Zeichen, das an jede Spaltenposition geschrieben wurde. Dies kann bei der Verarbeitung der Ausgabe von mandoc (1) hilfreich sein.


Das Linux- colHandbuch (unter Ubuntu) enthält nicht den letzten Satz (aber es funktioniert genauso).

Unter Linux MAN_KEEP_FORMATTINGkann es auch hilfreich sein, die Umgebungsvariable zu deaktivieren (oder auf eine leere Zeichenfolge zu setzen), und Sie grepkönnen dies tun , ohne die Ausgabe von manthrough zu übergeben col -b.

Kusalananda
quelle
Ich denke (wie ich es auf einem Arch- und einem Ubuntu-System getestet habe), dass dies unter Linux nicht oder nicht mehr notwendig ist. Auf beiden Systemen ist das NAMEin der Bash-Anleitung nur NAMEnein \b.
Terdon
@terdon Ich habe die Erwähnung von macOS nicht zuerst bemerkt, daher habe ich angenommen, dass ein falsch konfiguriertes Linux-System in Frage kommt. Ich habe jetzt die Linux-Bits abgeschnitten.
Kusalananda
Sie haben nichts verpasst, ich habe das OP gefragt, welches Betriebssystem sie verwenden, weil ich unter Linux nicht reproduzieren konnte. Sie sagten, macOS, und ich habe es jetzt hinzugefügt. Und ich habe nicht angedeutet, dass Sie sich geirrt haben. Soweit ich weiß, gibt es Linux-Distributionen, in denen die MAN_KEEP_FORMATTINGVariable genau so funktioniert, wie Sie es sagen. Ich wollte nur darauf hinweisen, dass dies nicht immer der Fall ist.
Terdon