Como excluir linhas em branco a partir da linha 5

10

Eu tenho isto:

sed -i '/^$/d' temp_spec.rb

que remove linhas em branco e funciona bem. Como posso fazer isso apenas para as linhas 5-999 (ou, idealmente, 5 para o final do arquivo).

Eu tentei:

sed -n5,999 -i '/^$/d' temp_spec.rb
sed '5,999!d/^$/d' temp_spec.rb

mas nem funcionou (sem erros).

Michael Durrant
fonte
Só para ter certeza: você deseja manter as linhas 1 a 4, independentemente de estarem em branco ou não, ou deseja excluir as linhas 1 a 4, independentemente de estarem em branco ou não? (Até agora, eu assumi o primeiro, mas o segundo comando que você tentou me faz pensar.)
Uwe

Respostas:

12

Se você deseja excluir todas as linhas em branco que começam com a linha 5 e manter as linhas de 1 a 4, use

sed -i '5,${;/^$/d;}' temp_spec.rb

Como {é o operador de agrupamento, o primeiro comando 5,${significa "da linha 5 até o final da entrada ( $), execute os seguintes comandos até a correspondência }". Os comandos entre {e }podem ser prefixados novamente por endereços; portanto, o comando interno /^$/dsignifica "se não houver nada entre o início ( ^) e o final ( $) da linha, exclua-o". Os comandos Sed podem ser separados por ;. (Esse é um recurso mal documentado do sed. É suportado pela maioria das implementações do sed, mas não é totalmente portátil .) Como observado por Hauke, o ;depois {é opcional; o anterior }é necessário, no entanto.

Se você deseja excluir todas as linhas em branco iniciadas na linha 5 e também as linhas 1 a 4, é mais fácil:

sed -i '1,4d;/^$/d' temp_spec.rb
Uwe
fonte
Agradável. Eu não sabia que os endereços podem ser aninhados dessa maneira. Para mim, funciona sem a liderança ;também.
Hauke ​​Laging
Sim, você está certo sobre o primeiro ;.
Uwe
@Hauke ​​Laging Você pode separar comandos em um script sed por ';' em vez disso, coloque-os em linhas separadas. Esse é um recurso "não documentado".
Predrag Punosevac
4

Outra opção usando o awk:

awk 'NR<5||/./'
Lri
fonte
2
sed '5,${s/^$//; t delete; b end; : delete; d; : end;}' temp_spec.rb

Editar 1:

Eu devo explicar isso, assim ...

Isso é desnecessariamente complicado. Eu não sabia que intervalos de endereços são permitidos dentro {}. Então eu tive que expressar "excluir linhas vazias" de maneira diferente. O comando principal é tqual é o modo de sed if ... then. Tteria sido mais fácil, mas está disponível apenas para o GNU sed. Eu cito a página de manual:

t label: Se como /// fez uma substituição bem-sucedida desde a última leitura da linha de entrada e desde o último comando t ou T, ramifique para label; se o rótulo for omitido, ramifique para o final do script.

Eu abuso o famoso scomando. Não deve substituir nada, mas apenas testar se a linha está vazia. Portanto, ele substitui uma linha vazia por uma linha vazia (poderia usar algo como substituição, pois a linha é excluída de qualquer maneira).

Se sfez uma "substituição", a linha está vazia. Nesse caso, o comando ddeve ser executado. Caso contrário, nada deve ser feito. Como tnão pula no caso de uma sação, preciso do comando branch bpara pular para o final do script. : labelsão alvos de ramificação. Como gotonaquela época na idade das trevas (quando o sed foi inventado ... te-hee).

Outra opção seria s"substituir" todas as linhas não vazias, facilitando so comando mais complicado, mas o restante:

sed '5,${s/^\(..*\)$/\1/; t end; d; : end;}' input

^..*$significa "linha não vazia" e \1significa "o conteúdo dos primeiros colchetes".

Hauke ​​Laging
fonte
Um pouco de explicação por causa do OP (eu posso sentir seu cérebro tentando rastejar para fora através dos ouvidos lendo este ...)
vonbrand