Grep-Ausgabe ohne nachgestellte Newline

8

Bitte beachten Sie diesen Ausschnitt:

X=$(grep -m1 'some-pattern' some-file | sed -n 's/.* //p')

Ich möchte das letzte Wort in eine Variable einfügen, wenn eine Musterbedingung für Zeilen in einer beliebigen Textdatei übereinstimmt

Mein Problem ist, dass die Variable Xam Ende CR oder LF oder CRLF hat, abhängig von der Quelldatei, die ich entfernen möchte, da dies den späteren Betrieb beeinträchtigt, den ich beabsichtige.
Ich habe sogar so etwas versucht wie:

X=$(grep -m1 'some-pattern' some-file | sed -n 's/.* \([A-Za-z]\+\)/\1/p')

Daher wird erwartet, dass die sedAusgabe begrenzt wird, [A-Za-z]+aber es gibt immer noch diese störenden Bytes innerhalb der X-Variablen.

Wie kann ich es loswerden, ohne Sehen , zu viel Code , welche Bytes am Ende sind mit xxddann cutes und ähnliche Komplikationen?

Zetah
quelle

Antworten:

4

Es scheint awkeine bessere Wahl für Ihre Bedürfnisse zu sein, da diese Probleme nicht bestehen, da Felder und Datensätze verwendet werden können:

x=$(awk '/some-pattern/ { sub(/\r$/, "") ; printf("%s", $NF) ; exit }' some-file)

Durch die Ersetzung wird Ihr Problem mit CRLF-Zeilenenden vermieden.

sub(/\r$/, "")Entfernt die nachfolgende CR, falls vorhanden. So awkbehandelt \nwie das Trennzeichen für Datensätze (Zeilen), müssen Sie es nicht entfernen, da es nicht in den Daten enthalten ist, die angezeigt werden.

printf("%s", $NF)$NFGibt das letzte Feld ( ) ohne nachfolgende Zeilenumbruch aus ( printund einige andere awkFunktionen fügen standardmäßig eine neue Zeile hinzu).

exitgeschieht nach den ersten beiden Aktionen - dies entspricht dem m1in Ihrer grepBefehlszeile. Dies stellt sicher, dass awkExits nach der Ausführung der beiden vorherigen Befehle ausgeführt werden. Da diese Befehle bei einer Übereinstimmung ausgegeben werden und awk Daten auf FIFO-Weise auswertet, wird nur die erste Übereinstimmung gedruckt.

Chris Down
quelle
Danke, es sieht elegant aus, aber leider ist CRLF immer noch drinnenX
zetah
:) Jetzt sieht es nicht mehr elegant aus und es ist immer noch nicht gut
zetah
@zetah - Es wird keine geben CR, aber es wird eine geben LF. Es fiel mir schwer zu verstehen, was Sie von der Frage wollen, hoffentlich macht meine Bearbeitung, was Sie wollen.
Chris Down
OK, diesmal tut es gut - das letzte Wort in einer Zeile ausgeben, wenn diese Zeile eine Musterbedingung erfüllt - weiß nicht, vielleicht ist es mir klar, weil ich dieses Problem habe und es dann als nicht-englischer Muttersprachler schwer zu erklären ist . Wie auch immer, ich werde ein bisschen länger warten, wenn jemand dies grep/sedstattdessen mit einer Lösung anspricht awk(was ich nicht verstehe), und wenn nicht, werde ich es verwenden. Danke
Zetah
@zetah - Ich werde eine Erklärung hinzufügen, damit Sie es eine Sekunde besser verstehen können.
Chris Down
7

Das ``oder $()entfernt die neue Zeile vom Ende, aber um dies programmgesteuert zu tun, verwenden Sie tr.

grep -m1 'some-pattern' some-file | sed -n 's/.* //p' | tr -d '\012\015'

Dadurch werden der Wagenrücklauf und / oder die neue Zeile aus der Zeichenfolge entfernt.

Das Problem könnte sein, wie Sie das Ergebnis dann ausgeben . echoFügt beispielsweise standardmäßig eine neue Zeile hinzu. Möglicherweise möchten Sie echo -noder verwenden printf.

Arcege
quelle
Dadurch werden auch Wagenrückläufe entfernt, die in der gesamten Zeichenfolge auftreten können und möglicherweise nicht erwünscht sind.
Chris Down
Ja, obwohl es möglich ist, einen Wagenrücklauf in eine einzelne Zeile einzubetten, ist dies äußerst selten. Dadurch -m1wird sichergestellt, dass nur eine Zeilenausgabe vorhanden ist, bei der der Wagenrücklauf aller Wahrscheinlichkeit nach am Ende erfolgen würde.
Arcege
ah tr... interessant, funktioniert sowohl mit LF- als auch mit CRLF-Dateien. Ich würde \010\013aus irgendeinem Grund denken und \f\rfunktioniert auch richtig. Über das Ergebnis: Ich setze die Ausgabe nicht in eine Variable, sondern als Variable, die $()in einem Muster für die grepÜbereinstimmung eingeschlossen ist some pipe | grep -o " $(...) ". Vielen Dank für Kommentare
Zetah
3

Ich bevorzuge diesen Weg

grep -m1 'some-pattern' some-file | sed -n 's/.* //p' | tr -d '\n'
Steven Penny
quelle
2

Das funktioniert bei mir:

grep -m1 'some-pattern' some-file | sed -n 's/.* //p' | tr -d "\n" | tr -d "\r"
Funky_Pandy
quelle
0

Warum nicht einfach seddie [\r\f]Bereinigung durchführen lassen:

# using Bash's $'string' idiom (that decodes ANSI C escape sequences)
# cf. http://wiki.bash-hackers.org/syntax/quoting#ansi_c_like_strings
- X="$(grep -m1 'some-pattern' some-file | sed -n 's/.* //p')"
+ X="$(grep -m1 'some-pattern' some-file | sed -n -e $'s/[\r\f]*$//' -e 's/.* //p')"

Bei Ihrem zweiten Ansatz fehlt ein endgültiger regulärer Ausdruck, um die nachfolgende CR zu erfassen \r.

# sample code to remove trailing \r with sed
# cf. http://en.wikipedia.org/wiki/Regular_expression#POSIX_character_classes
printf 'a b c\r' | sed -n 's/^.* \([[:alpha:]]\{1,\}\)/\1/p' | od -c
printf 'a b c\r' | sed -n 's/^.* \([[:alpha:]]\{1,\}\)[[:space:]]*/\1/p' | od -c

# keeps trailing space after c
printf 'a b c \r' | sed -n 's/^.* \([[:alpha:] ]\{1,\}\)[[:space:]]*/\1/p' | od -b
Tschad
quelle
0

Die normale Version von grep (einschließlich grep -P) gibt immer einen Zeilenvorschub mit seiner Übereinstimmung aus. Wenn Sie also nur ein Ergebnis haben (oder nur den endgültig hinzugefügten Zeilenvorschub entfernen möchten), reicht es aus, einfach das endgültige Zeichen zu entfernen der Ausgabe, die Sie tun können, indem Sie es durchleiten head -c-1.

Jon
quelle