Ersetzen Sie eine Zeile in einer Datei durch Teile dieser Zeile

Ersetzen Sie eine Zeile in einer Datei durch Teile dieser Zeile

Ich habe eine Liste der installierten Programme auf meiner Ubuntu-Box mitapt list --installed

Hier ist ein Ausschnitt der Liste

wdiff/xenial,now 1.2.2-1build1 amd64 [installed,automatic]
wget/xenial-updates,xenial-security,now 1.17.1-1ubuntu1.5 amd64 [installed]
whiptail/xenial,now 0.52.18-1ubuntu2 amd64 [installed]
xauth/xenial,now 1:1.0.9-1ubuntu2 amd64 [installed]
xdg-user-dirs/xenial-updates,now 0.15-2ubuntu6.16.04.1 amd64 [installed]
xfsprogs/xenial-updates,now 4.3.0+nmu1ubuntu1.1 amd64 [installed]
xkb-data/xenial,now 2.16-1ubuntu1 all [installed]

Ich brauche den Programmnamen und die Version. Beispiel:
wdiff/xenial,now 1.2.2-1build1 amd64 [installed,automatic] wird
wdiff 1.2.2-1build1

Ich habe diesen Befehl entwickelt, der funktioniert.

apt list --installed  | sed -r 's@/@ @g' | awk '{print $1 "\t" $3}'  | sort -u

Ich möchte wissen, wie ich nur sed verwende, um eine neue Datei mit Teilen der Eingabedateizeile zu erstellen.

Dieser reguläre Ausdruck: ^([^\/]+)\/[^\s]+\s([^\s]+)

  • Erfassen vom Zeilenanfang bis zum ersten /
  • Ignorieren Sie das erste Leerzeichen
  • Erfassen Sie nach dem ersten Leerzeichen bis zum zweiten Leerzeichen

Und ich sollte in der Lage sein, Sed-Rückverweise auf die Erfassungsgruppen zu verwenden und die neue Ausgabe zu erstellen.

apt list --installed | sed -r 's/^([^\/]+)\/[^\s]+\s([^\s]+)/\1 \2/'

Allerdings scheint das Ergebnis nicht meinen Erwartungen zu entsprechen.

wdiff   [installed,automatic]
wget/xenial-updates,xenial-security,now 1.17.1-1ubuntu1.5 amd64 [installed]
whiptail    [installed]
xauth   [installed]
xdg-user-dirs/xenial-updates,now 0.15-2ubuntu6.16.04.1 amd64 [installed]
xfsprogs/xenial-updates,now 4.3.0+nmu1ubuntu1.1 amd64 [installed]
xkb-data    [installed]

Was läuft schief?

Antwort1

Was läuft falsch? Sie haben die falsche Gruppe erfasst und nicht bis zum Ende der Eingabezeichenfolge nach der letzten Übereinstimmung, die Sie behalten wollten, verworfen, sondern nur bis zum nächsten Nicht-Leerzeichen.

sed -r 's/^([^\/]+)\/[^\s]+\s([^\s]+)/\1    \2/'

([^/]+)   #capture everything up to /, OK
/         #discard the /. OK
[^\s]     #discard the next non white-space group, this is the bit you actually want
\s        #discard the whitespace
([^\s]+)  #capture the next non-whitespace group
#leave anything after the last non-whitespace found

Sie haben dies wahrscheinlich getan, weil die Lesbarkeit mit all den Escapezeichen schlecht war. Wenn Sie es bereinigen, hilft es Ihnen beim Debuggen

sed -E 's|([^/]*)[^ ]* +([^ ]*).*|\1 \2|' infile | column -t

([^/]*)    #capture up to the /
[^ ]* +    #discard until the space and any spaces
([^ ])     #capture the next character group until a space
.*         #discard to the end of the string

Sofern Sie keine globale Übereinstimmung ( s///g) angegeben haben, benötigen Sie den ^Anker nicht.

Verwenden Sie es |als Trennzeichen, um unnötige Escapezeichen in Ihrer passenden Zeichenfolge zu vermeiden.

Dies column -termöglicht eine bessere Ausrichtung als mehrere Leerzeichen.

Antwort2

Versuchen Sie den folgenden (nicht optimierten) regulären Ausdruck:

$ sed 's/\(^.*\)\(\/[^ ]* \)\([^ ]* \)\([^ ]* \)\([^ ]*\)/\1 \3/' infile
wdiff 1.2.2-1build1 
wget 1.17.1-1ubuntu1.5 
whiptail 0.52.18-1ubuntu2 
xauth 1:1.0.9-1ubuntu2 
xdg-user-dirs 0.15-2ubuntu6.16.04.1 
xfsprogs 4.3.0+nmu1ubuntu1.1 
xkb-data 2.16-1ubuntu1 

verwandte Informationen