Explique por favor sed script

1

Não consigo entender como esse script sed funciona:

echo -e "Line #1\n\n\n\nLine #2\n\n\nLine #3" | sed '1s/^$//p;/./,/^$/!d'

Suprime linhas vazias repetidas como cat -s Mas tenho algumas perguntas:

  1. Para qual 1s/^$//p ? Pelo que entendi, não faça nada com a primeira linha, mesmo se ela estiver vazia
  2. Este /./,/^$/ corresponde apenas antes do primeiro ^$ , como Line #1\n\n , e não corresponde a Line #1\n\n\n ?
  3. Os intervalos não são gananciosos por padrão no sed?

Para esclarecer a questão 3, tentei os próximos testes:

echo -e "Line #1\n\n\n\nLine #2\n\n\nLine #3" | sed -n '/#/,/#/p'

E o resultado foi:

Line #1



Line #2
Line #3

(então, é ganancioso)

Mas quando tentei:

echo -e "Line #1\n\n\n\nLine #2\n\n\nLine #3" | sed -n '/#1/,/#/p'

o resultado foi:

Line #1



Line #2

(agora parece não ser ganancioso)

    
por stand alone 20.02.2018 / 23:40

2 respostas

6

1s/^$//p imprime a primeira linha, se estiver vazia.

/./,/^$/ corresponde às linhas da primeira linha não vazia até a primeira linha vazia encontrada. Não é ganancioso no sentido de que um qualificador regex é: sed não pode olhar para o arquivo ou voltar atrás, então ele precisa parar na primeira vez que o padrão final corresponder.

Após a linha final, a busca pela linha inicial começa novamente, então a próxima linha não vazia novamente inicia o intervalo. Na verdade, o intervalo corresponde a linhas não vazias contíguas, além do primeiro vazio seguinte.

Como o intervalo é usado como /./,/^$/!d , todas as linhas não correspondentes são excluídas. Isso inclui a primeira linha, se estiver vazia, e é por isso que ela é impressa explicitamente pela primeira regra.

Sem a regra 1s/^$//p , a primeira linha será removida se estiver vazia, mesmo que não seja realmente "repetida".

$ echo $'\nfoo' | sed '1s/^$//p;/./,/^$/!d'

foo
$ echo $'\nfoo' | sed '/./,/^$/!d'
foo
$

Em seu teste, o intervalo /#/,/#/ é um pouco diferente, já que começa e termina com o mesmo padrão. Line #1 corresponde ao padrão inicial (assim as linhas vazias intervenientes são impressas) Line #2 corresponde ao final (as seguintes linhas vazias não são) e em Line #3 , o intervalo começa novamente.

No outro, o padrão inicial é /#1/ , mas isso só é encontrado uma vez na entrada.

    
por 20.02.2018 / 23:49
0

O ilkkachu deu uma ótima resposta, que cobriu todos os aspectos desse comando, incluindo a necessidade menos que óbvia da primeira parte da string sed; e incluindo o fato de que o "!" o personagem exclui as partes que NÃO correspondem, na prática, as linhas em branco repetitivas.

Ainda assim, é uma maneira estranha de fazer isso, quando existem opções mais fáceis, como mais -s , ou uniq disponíveis.

    
por 21.02.2018 / 04:39