
Ich habe eine Datei mit folgendem Inhalt
..\..\src\modules\core\abc\abc.cpp
..\..\src\modules\core\something\xyz\xyz.cpp
..\..\src\other_modules\new_core\something\pqr\pqr.cpp
..\..\src\other_modules\new_core\something\pqr\abc.cpp
Das Ergebnis, das ich erwarte, ist
..\..\src\abc\abc.cpp
..\..\src\xyz\xyz.cpp
..\..\src\pqr\pqr.cpp
..\..\src\pqr\abc.cpp
Wie kann ich dies mit sed erreichen?
Ich kann keinen regulären Ausdruck schreiben, um zwei Gruppen gleichzeitig zu erfassen.
- anfängliche Gruppe (....\src) - diese ist in allen Zeilen gleich
- Variablengruppe (abc\abc.cpp) oder (xyz\xyz.cpp) oder (pqr\pqr.cpp) oder (pqr\abc.cpp)
Antwort1
Mit BSD sed
oder neueren Versionen von GNU sed
(für ältere Versionen ersetzen Sie es -E
durch -r
):
sed -E 's#(.*\\src).*(\\[^\]+\\[^\]+$)#\1\2#' file.txt
#
s
wird als Trennzeichen für den Befehl substitution ( ) von verwendetsed
, um Mehrdeutigkeiten im Zusammenhang mit\
s in der Eingabe zu vermeiden.(.*\\src)
Spiele bissrc
zum Start und lege das Spiel in die erfasste Gruppe 1(\\[^\]+\\[^\]+$)
entspricht dem Teil mit zwei\
s bis zum Ende und wird in die erfasste Gruppe 2 eingefügt. Das.*
vorhergehende this entspricht allem zwischen der ersten und zweiten erfassten GruppeBeim Ersetzen haben wir die beiden erfassten Gruppen verwendet
POSIX-mäßig:
sed 's#\(.*\\src\).*\(\\[^\]\+\\[^\]\+$\)#\1\2#' file.txt
Beispiel:
% cat file.txt
..\..\src\modules\core\abc\abc.cpp
..\..\src\modules\core\something\xyz\xyz.cpp
..\..\src\other_modules\new_core\something\pqr\pqr.cpp
..\..\src\other_modules\new_core\something\pqr\abc.cpp
% sed -E 's#(.*\\src).*(\\[^\]+\\[^\]+$)#\1\2#' file.txt
..\..\src\abc\abc.cpp
..\..\src\xyz\xyz.cpp
..\..\src\pqr\pqr.cpp
..\..\src\pqr\abc.cpp
Antwort2
Alternative Lösungen:
Mit GNU grep
undpaste
grep
extrahiert die beiden Muster .*\\src
und (\\[^\]+){2}$
gibt sie in getrennten Zeilen aus. Die Ausgabe wird dann kombiniert mitpaste
$ grep -oE '.*\\src|(\\[^\]+){2}$' ip.txt | paste -d '' - -
..\..\src\abc\abc.cpp
..\..\src\xyz\xyz.cpp
..\..\src\pqr\pqr.cpp
..\..\src\pqr\abc.cpp
Mitperl
$ perl -pe 's/.*\\src\K.*(?=(\\[^\\]+){2}$)//' ip.txt
..\..\src\abc\abc.cpp
..\..\src\xyz\xyz.cpp
..\..\src\pqr\pqr.cpp
..\..\src\pqr\abc.cpp
Hier wird der Text zwischen den Mustern .*\\src
und (\\[^\\]+){2}$
durch positive Lookarounds gelöscht.
Antwort3
Erstellen Sie eine Datei mit Daten
-rwxr-xr-x. 1 sasi webApp 190 Oct 4 13:42 file.txt
Führen Sie den folgenden Befehl aus
[sasi@localhost temp]$ sed -E 's#(.*\\src).*(\\[^\]+\\[^\]+$)#\1\2#' file.txt
..\..\src\abc\abc.cpp
..\..\src\xyz\xyz.cpp
..\..\src\pqr\pqr.cpp
..\..\src\pqr\abc.cpp
[sasi@localhost temp]$
[sasi@localhost temp]$
[sasi@localhost temp]$
Antwort4
Warum sollte man das mit regulären Ausdrücken bearbeiten? Für die Pfadbereinigung sind keine regulären Ausdrücke erforderlich. Betriebssystemkernel verwenden keine regulären Ausdrücke, um Pfaden zu folgen.
Mit Awk verwenden wir einfach einen Backslash als Trennzeichen und Komponenten werden zu Feldern:
awk 'BEGIN { FS = OFS = "\\" } { print $1, $2, $3, $(NF-1), $NF }'