Utilice el comando sed para comprobar si existe una línea en particular; si no, agréguela

Utilice el comando sed para comprobar si existe una línea en particular; si no, agréguela

Quiero agregar más terminales al archivo /etc/securetty. Más específicamente, me gustaría agregar pts/ndónde nestá en el rango 0-9, si no existe. ¿Es esto posible mediante sedcomando? Así es como /etc/securettyson los contenidos de mi:

# Local X displays (allows empty passwords with pam_unix's nullok_secure)
pts/0
pts/1
pts/2
pts/3

Probé algo como:

sudo sed '+pts/3+a pts/4' /etc/securetty

lo que da el siguiente error:

sed: -e expression #1, char 3: extra characters after command

Respuesta1

Anotamos el número de pts/ cuando nos encontremos con la línea correspondiente. La -popción será autoprintlíneas. Cuando llegamos, eofsacamos el hash %hy lo pasamos a través del grepfiltro para determinar qué terminales no se imprimieron y usamos mappara preparar el formato para que eso suceda.

perl -lpe 'm|^pts/([0-9])$| and $h{$1}++;
   END{ print for map { "pts/$_" } grep { !$h{$_} } 0 .. 9; }
' /etc/securetty

Inicializamos el hold spacecon los números 0 1 2 ... 9. Cada vez que encontramos la pts/[0-9]línea, la recortamos del espacio de espera. En eof, nos apoderamos del espacio de espera y, si se encuentra algún número, lo masajearemos en el formato adecuado y lo imprimiremos.

sed -e '
   # initialize the hold space with 0 1 ... 9
   1{x;s|.*|'"$(echo {0..9})"'|;x}

   # whatever be the line, it needs to be printed
   p

   # we meet a valid pts/ line
   \|^pts/[0-9]$|{
      # the hold space gets appended to the pattern space
      G
      # grab what is the pts number and search for it in the hold and
      # delete itand store back the changes into hold space.
      s|^pts/\([0-9]\)\n\(.*\)\1 |\2|;h
   }

   # weve not arrived at the eof and weve processed the input so go no further
   $!d

   # we are at the eof, so we bring back the hold space. just in case all
   # numbers were dealt with up, we simply bail out. Else, prepend the str 
   # pts/ to the numbers present and simply were home
   g;/[0-9]/!d;s/ //g
   s|[0-9]|pts/&\n|g;s/.$//

   # *TIP*: Sprinkle the l, list pattern space at various places to see 
   # whats going on.

' /etc/securetty 

Respuesta2

Para agregar una sola línea cuando falta, se puede eliminar cada aparición y agregarla al final:

sed -n '/pattern/!p;$a pattern'

Pero es desagradable repetir eso durante 10 patrones.

sed '/pts\/[0-9]/d;$a pts/0 ...

fallará si se va a eliminar la última línea. Entonces al revés, asumiendo que la primera línea es la única que comienza con #:

sed '/#/a pts/0\
pts/1\
pts/2\
pts/3\
pts/4\
pts/5\
pts/6\
pts/7\
pts/8\
pts\9
/pts\/[0-9]/d'

Asqueroso. Sugiero utilizar una herramienta diferente en este caso.

Respuesta3

Elimine cualquiera o todas pts/Nlas líneas, luego agréguelas todas nuevamente en:

{ grep -xv '^pts/[0-9]$' /etc/securetty; printf 'pts/%d\n' {0..9}; } > /etc/securetty.new
cat /etc/securetty.new
mv /etc/securetty.new /etc/securetty

También puedes hacer esto de una sola vez con tu herramienta de procesamiento de texto favorita, por ejemplo.ed

ed -s /etc/securetty <<IN
g/^pts\/[0-9]$/d
.r ! printf pts/\%d\\\n {0..9}
,p
q
IN

(reemplazar ,pcon wpara editar en el lugar) osed

{ printf '%s\\\n' '$a' pts/{0..8}
printf '%s\n' 'pts/9' '/^pts\/[0-9]$/d'
} | sed -f- /etc/securetty

que es más o menos lo mismo que simple

sed '$a\
pts/0\
pts/1\
pts/2\
pts/3\
pts/4\
pts/5\
pts/6\
pts/7\
pts/8\
pts/9
/^pts\/[0-9]$/d' /etc/securetty

(usarsed con-ipara editar el archivo en el lugar)

Respuesta4

sedprocesa el archivo línea por línea y es muy difícil hacer que "recuerde" cualquier información entre líneas.

Puede utilizar greppara averiguar si un archivo contiene un patrón determinado; Con -f, puedes suministrar múltiples patrones al mismo tiempo. Lo siguiente genera la lista completa pts/0... pts/9, luego elimina los patrones que ya están presentes en el archivo dado y agrega los restantes al archivo:

#!/bin/bash
printf 'pts/%d\n' {0..9} \
| grep -vFf "$1"  - >> "$1".new
mv "$1".new "$1"

información relacionada