Parece que isso é algo que deveria ter sido respondido aqui antes, mas minha busca ainda não encontrou o caso exato.
Tenho um arquivo (na verdade, um arquivo de hosts) com uma linha de sinalização. Tenho alguns scripts que adicionam e removem linhas antes da linha de sinalização.
Mas há o risco de que o processo de remoção deixe linhas em branco criadas pelo processo de adição.
Então, eu gostaria de um método para remover quaisquer linhas em branco imediatamente antes da linha de sinalização no arquivo.
Parece que isso deveria ser possível com sed
, mas os exemplos online que encontrei não incluem esse caso (ironicamente, eles incluem o caso oposto - adicionar uma linha em branco antes de uma linha correspondente)
Existe uma maneira simples de fazer isso?
Não é necessário usar sed
, qualquer outra ferramenta padrão de manipulação de texto também serviria.
É preferível editar no local, mas se realmente necessário, você pode copiar para um arquivo temporário e depois copiar de volta.
Entrada de amostra (não é possível postar os dados precisos)
10.8.7.6 static-host1
10.8.7.7 static-host2
10.8.8.5 static-host3
10.8.8.6 static-host4
# Start of dynamic section
10.9.9.8 dynamic-group1-host1
10.9.9.9 dynamic-group1-host1
10.9.8.7 dynamic-group2-host1
10.9.8.8 dynamic-group2-host2
# End of dynamic section
10.10.11.12 static-host5
10.10.11.13 static-host6
10.10.11.17 static-host7
10.10.11.18 static-host8
Saída de amostra
10.8.7.6 static-host1
10.8.7.7 static-host2
10.8.8.5 static-host3
10.8.8.6 static-host4
# Start of dynamic section
10.9.9.8 dynamic-group1-host1
10.9.9.9 dynamic-group1-host1
10.9.8.7 dynamic-group2-host1
10.9.8.8 dynamic-group2-host2
# End of dynamic section
10.10.11.12 static-host5
10.10.11.13 static-host6
10.10.11.17 static-host7
10.10.11.18 static-host8
Seria razoável para qualquer solução assumir que a última linha antes dos espaços em branco serem removidos sempre começa com o mesmo padrão, normalmente um endereço RFC1918 (por exemplo, 10. ou 192.168.)
Quanto ao outro comentário, sim, linhas em branco são desejáveis para facilitar a leitura, e é por isso que meu script as adiciona entre as seções que ele adiciona. Ao remover uma seção, eu poderia remover "quaisquer linhas em branco antes da primeira linha da seção", mas isso se resume ao mesmo problema: remover uma ou mais linhas em branco antes de uma linha que corresponda a um padrão.
(espero que seja óbvio) não é aceitável simplesmente remover todas as linhas em branco do arquivo.
Solução
Explicação
O fragmento entre
: load
eb load
é um laço que acrescentaN
linhas ( ) ao espaço de padrão, enquanto todo o espaço de padrão consiste em linhas "vazias": caracteres daspace
classe de caracteres (na localidade POSIX, aspace
classe de caracteres inclui exatamente <espaço>, <avanço de formulário>, <nova linha>, <retorno de carro>, <tabulação> e <tabulação vertical>; pode incluir mais caracteres na sua localidade). Quando houver um caractere que não pertença àspace
classe de caracteres, o laço para de acrescentar linhas e o script prossegue.Em outras palavras, o script carrega linhas no espaço de padrões até que uma linha não "vazia" apareça ou a entrada termine. Então, o espaço de padrões é um trecho de zero ou mais linhas "vazias" seguidas por, no máximo, uma linha não "vazia".
A linha de código com
# End of dynamic section
substitui (s
) as linhas "vazias" iniciais no espaço do padrão por nada, se e somente se a última linha carregada for exatamente# End of dynamic section
e não for a única linha carregada.Por fim,
sed
imprime o espaço do padrão resultante e inicia um novo ciclo (se ainda não estiver no final da entrada), pois esse é seu comportamento padrão.Notas
Se você quiser que o script detecte linhas realmente vazias , substitua cada uma
[[:space]]
por apenas\n
. Alternativamente, faz sentido usar[ \t\n]
or[[:blank:]\n]
(na localidade POSIXblank
inclui exatamente <espaço> e <tab>, mas pode incluir mais caracteres na sua localidade). Escolha o que for mais adequado às suas necessidades.Cada linha sendo exata
# End of dynamic section
é especial.