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).


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

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||/./'

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".


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.