Use o comando sed para verificar se existe uma determinada linha, se não, adicione-a

2

Eu quero adicionar mais terminais ao arquivo /etc/securetty . Mais especificamente, gostaria de adicionar pts/n , em que n está no intervalo 0-9 , se não existir. Isso é possível através do comando sed ? O seguinte é como o conteúdo do meu /etc/securetty é:

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

Eu tentei algo como:

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

que apresenta o seguinte erro:

sed: -e expression #1, char 3: extra characters after command
    
por skrowten_hermit 12.04.2017 / 13:06

5 respostas

3

Anotamos os pts / number quando encontramos a linha correspondente. A opção -p irá autoprint linhas. Quando alcançamos o eof extraímos o hash %h e o passamos pelo filtro grep para determinar quais terminais não foram impressos e usamos map para preparar o formato para que isso acontecesse.

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

Inicializamos o hold space com números 0 1 2 ... 9. Sempre que encontramos a linha pts/[0-9] , copiamos isso do espaço de espera. Em eof , obtemos espaço de espera e, se algum número for encontrado, será massageado no formato correto e impresso.

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\(.*\) ||;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 
    
por 12.04.2017 / 15:07
1

Para adicionar uma única linha quando estiver faltando, remova cada ocorrência e acrescente-a no final:

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

Mas é desagradável repetir isso por 10 padrões.

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

falhará se a última linha for removida. Então, o contrário, assumindo que a primeira linha é a única começando com # :

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

Desagradável. Eu sugiro usar uma ferramenta diferente neste caso.

    
por 12.04.2017 / 15:00
1

Remova qualquer / todas as linhas pts/N e adicione-as novamente:

{ 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

Você também pode fazer isso de uma só vez com sua ferramenta de processamento de texto favorita. ed

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

(substitua ,p por w para edição no local) ou sed

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

que é praticamente o mesmo que simples

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

(use sed com -i para editar o arquivo no local)

    
por 12.04.2017 / 15:00
1

Você pode pesquisar o arquivo de segurança e adicionar entradas ausentes da seguinte forma:

for x in 0 1 2 3 4 5 6 7 8 9
do 
   grep "pts/${x}" /etc/securetty || echo "pts/${x}" >> /etc/securetty
done
sort /etc/securetty -o /etc/securetty
    
por 12.04.2017 / 16:30
0

sed processa o arquivo linha por linha e é muito difícil fazer com que ele "lembre" de qualquer informação entre linhas.

Você pode usar grep para descobrir se um arquivo contém um determinado padrão; com -f , você pode fornecer vários padrões ao mesmo tempo. O seguinte gera a lista completa pts/0 .. pts/9 , remove os padrões já presentes no arquivo fornecido e adiciona os restantes no arquivo:

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