Verwenden Sie sed, um einen Teilstring zwischen zwei doppelten Anführungszeichen zu setzen


14

Ich habe eine Akte

xyz... rsync: "/home/path/to/file": Permission denied (13) rsync:
"/home/path/to/file1": Permission denied (13) rsync:
"/home/path/to/file2": Permission denied (13) rsync:
"/home/path/to/file3": Permission denied (13)

Jetzt möchte ich nur die Dateipfade extrahieren und in einer anderen Datei speichern. Ausgabedatei ist wie folgt:

/home/path/to/file 
/home/path/to/file1 
/home/path/to/file2
/home/path/to/file3

Mit sed oder awk wie kann ich das machen?

Ich habe es versucht, sed -n '/"/,/"/p' myfileaber es funktioniert nicht.


3
Um die Abstimmung zu schließen - Wie kann dies möglicherweise Off-Topic sein? Es geht um Shell-Programmierung !! Das ist PROGRAMMIEREN, das für Stack Overflow auf dem neuesten Stand ist!
Jonathan Leffler

2
Willkommen bei Stack Overflow. Wie Sie sehen, haben wir gelegentlich Probleme damit, dass Leute mit juckenden Triggerfingern perfekt gute Fragen (wie diese) mit schlechten Gründen für das Schließen schließen. Es kommt nicht allzu oft vor (oder ich sehe das Problem nicht allzu oft), aber es kommt vor. Vergiss nicht, die FAQ zu lange zu lesen .
Jonathan Leffler

Antworten:


17

Sie können stderr Ihres rsync-Befehls an ein awk-Skript übergeben:

awk -F '"' '{print $2}' 

Oder zu einem Befehl wie diesem:

cut -d'"' -f2

2
Oder kürzer:cut -d\" -f2

@AndersJohansson: Danke, ich habe deinen Befehl cut hinzugefügt, um auch zu antworten.
Anubhava

Ich denke, das wird nicht funktionieren. Wie Sie sehen können, ist die Feldnummer des Dateipfads nicht fest $ 2 oder f2. Danke!

Tatsächlich schreibt rsync immer zuerst den Dateipfad zwischen "und "auf stderr.
Anubhava

1
@ Jam88: Eigentlich wird es funktionieren, weil anubbhava es so geschrieben hat. Das Feldtrennzeichen ist auf doppelte Anführungszeichen gesetzt. Das bedeutet, dass alles bis zum ersten Anführungszeichen (möglicherweise eine leere Zeichenfolge) ist $1; alles zwischen dem ersten und dem zweiten Anführungszeichen ist $2; und alles nach dem zweiten doppelten Anführungszeichen ist in $3( $4, ...). Der Dateiname steht (anscheinend) immer zwischen den ersten beiden Anführungszeichen, daher sollte diese Lösung funktionieren (und tat es, als ich sie getestet habe).
Jonathan Leffler

6

Verwenden von sed:

sed 's/^[^"]*"\([^"]*\)".*/\1/'

Das sucht nach: Zeilenanfang, einer Reihe von Nicht-Anführungszeichen, einem doppelten Anführungszeichen, einer Reihe von Nicht-Anführungszeichen, einem doppelten Anführungszeichen und allem anderen in der Zeile und ersetzt es durch das erfasste Material.

$ sed 's/^[^"]*"\([^"]*\)".*/\1/' <<'EOF'
> xyz... rsync: "/home/path/to/file": Permission denied (13) rsync:
> "/home/path/to/file1": Permission denied (13) rsync:
> "/home/path/to/file2": Permission denied (13) rsync:
> "/home/path/to/file3": Permission denied (13)
> EOF
/home/path/to/file
/home/path/to/file1
/home/path/to/file2
/home/path/to/file3
$

Testen Sie auf RHEL 5 Linux mit GNU sed, aber nur mit Funktionen, die in der 7. Edition von UNIX ™ funktionieren würden sed.

Eine etwas einfachere Möglichkeit ist übrigens die Verwendung von zwei Ersatzbefehlen. ändere alles bis einschließlich des ersten Anführungszeichens in eine leere Zeichenkette (das ist eine Folge von null oder mehr nicht Anführungszeichen, gefolgt von einem doppelten Anführungszeichen); ändere alles nach dem, was jetzt das erste doppelte Anführungszeichen ist, in nichts:

sed 's/^[^"]*"//; s/".*//'

Übrigens druckt der von Ihnen ausgeführte Befehl (`sed -n '/" /, / "/ p') von einer Zeile mit einem doppelten Anführungszeichen in die nächste Zeile mit einem doppelten Anführungszeichen, ohne die Zeilen zu bearbeiten. Aus diesem Grund schien es bei Ihnen nicht zu funktionieren - es hat getan, was Sie gefragt haben, aber was Sie von ihm verlangt haben, war nicht das, was Sie von ihm verlangt haben.

In Bezug auf die Effizienz ist es unwahrscheinlich, dass es einen messbaren Unterschied in der Leistung gibt. In Bezug auf die Wartungsfreundlichkeit vermute ich, dass letztere die Gehirnzellen weniger belastet.


1

Wenn Ihre Version von grepPerl-regexp unterstützt:

grep -oP '(?<=")/home/.*?(?=")' file >> anotherfile

Ergebnisse:

/home/path/to/file
/home/path/to/file1
/home/path/to/file2
/home/path/to/file3

Sie können dies auch weniger streng gestalten, um bei Bedarf eine Übereinstimmung zwischen den Doppel zu erzielen:

grep -oP '(?<=")[^"]*' file >> anotherfile

Müssen Sie das .*Non-Gierige mit .*?nur für den Fall machen, dass es später in der Zeile ein zusätzliches doppeltes Anführungszeichen gibt? Oder [^"]*anstelle von verwenden .*?
Jonathan Leffler

-1

Verwenden Sie den Operator >>, um alle Ausgaben in einer Datei zu speichern.

Mögen

grep -r "pattern" * >> file.txt

Ändern Sie dies einfach für Ihr spezifisches Szenario, indem Sie sed anhängen

>> filename

zum Befehl


Das grep -rführt eine rekursive Suche durch alle in den Argumenten ( *) aufgelisteten Verzeichnisse durch . Es ist nicht klar, welches Muster Sie im Sinn haben, aber es grepwird die ganze Linie erfassen. Der Zweck der Übung besteht darin, Informationen aus einem Teil einer Zeile zu sammeln. Wenn Sie GNU verwenden grep, gibt es Möglichkeiten, dies zu tun ( -o); Diese sind nicht standardisiert (außer insofern, als GNU einen De-facto-Standard definiert). Ähnliches gilt für die Verwendung von regulären PCRE-Ausdrücken. Das sind andere GNU-Erweiterungen. Sie sind in Ordnung, wenn Sie GNU haben grepund nicht vorhaben, auf Plattformen zu arbeiten, auf denen GNU grepnicht standardmäßig verfügbar ist.
Jonathan Leffler

Tut mir leid, dass ich das verpasst habe, ich dachte, er wollte im Allgemeinen wissen, was zu tun ist, um die Ausgabe in eine Datei zu packen, und grep war nur ein Beispiel.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.