Reemplazar una línea en un archivo con partes de esa línea

Reemplazar una línea en un archivo con partes de esa línea

Obtuve una lista de programas instalados en mi Ubuntu Box usandoapt list --installed

Aquí hay un fragmento de la lista.

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]

Necesito el nombre y la versión del programa. Por ejemplo:
wdiff/xenial,now 1.2.2-1build1 amd64 [installed,automatic] se convierte
wdiff 1.2.2-1build1

Ideé este comando que funciona.

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

Me gustaría saber cómo usar solo sed para crear un archivo nuevo con partes de la línea del archivo de entrada.

Esta expresión regular: ^([^\/]+)\/[^\s]+\s([^\s]+)

  • Captura desde el inicio de la línea hasta la primera /
  • Ignorar hasta el primer espacio en blanco.
  • Capturar después del primer espacio en blanco al segundo espacio en blanco

Y debería poder utilizar referencias inversas de sed a los grupos de captura y crear el nuevo resultado.

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

Sin embargo, parece que el resultado no coincide con mis expectativas.

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]

¿Qué está pasando mal?

Respuesta1

¿Qué está pasando mal? Capturó el grupo equivocado y no lo descartó hasta el final de la cadena de entrada después de la última coincidencia que deseaba conservar, solo hasta el siguiente sin espacio en blanco.

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

Probablemente terminaste haciendo esto debido a la mala legibilidad de todos los escapes. Si lo limpias te ayudará a depurar

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

A menos que haya especificado una coincidencia global ( s///g), no necesita el ^ancla.

Úselo |como separador para evitar escapes innecesarios en su cadena coincidente

Hace column -tun mejor trabajo de alineación que los espacios múltiples.

Respuesta2

Pruebe la siguiente expresión regular (no optimizada):

$ 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 

información relacionada