Remova o caractere de nova linha apenas a cada N linhas


16

Ao processar o texto, preciso remover o caractere de nova linha a cada duas linhas.

Texto de amostra:

this is line one
and this is line two
the third and the
fourth must be pasted too

Saída desejada:

this is line one and this is line two
the third and the fourth must be pasted too

Eu tentei um whileloop, mas um loop while é uma prática ruim. É possível fazê-lo usando trou qualquer outro comando?


4
O título diz "todas as N linhas", mas na pergunta e no exemplo é "a cada 2 linhas". A maioria das respostas funciona apenas para N = 2. Você está procurando algo que funcione para todos os N?
precisa saber é o seguinte

Essa é a chave. Todos respondeu por 2 linhas, mas eu precisaria usar N = 3 ou N = 4
jomaweb

Respostas:


24

paste(também um utilitário simples padrão do POSIX tr) é sua ferramenta para isso.

Supondo que você queira que esses caracteres de nova linha sejam substituídos por um espaço em vez de apenas removidos, como na sua amostra:

paste -d ' ' - - < file

Ou:

paste -sd ' \n' file

Substitua ' 'por '\0'se você realmente deseja removê-los.

Para substituir 2 de 3:

paste -sd '  \n' file

1 de 3, começando com o segundo:

paste -sd '\n \n' file

E assim por diante.

Outra coisa boa pasteé que ela não deixará uma linha não terminada. Por exemplo, se você remover todas as novas linhas de um arquivo (como com tr -d '\n' < fileou tr '\n' ' ' < file), você acaba sem nenhuma linha, pois as linhas precisam ser finalizadas com um caractere de nova linha. Portanto, geralmente é melhor usar pasteisso (como em paste -sd '\0' fileou paste -sd ' ' file) que adicionará o caractere de nova linha à direita necessário para ter um texto válido.


11

Com o moderno GNU sed

sed -rz 's/\n([^\n]*\n)/ \1/g' sample.text

E awk

awk '{getline line2;print $0, line2}' sample.text

3
Essa sedabordagem significa reduzir o arquivo inteiro na memória (desde que ele não contenha NUL bytes) e fazer alguma substituição cara de regexp. Não vejo o benefício sobre a sed 'N;s/\n/ /'abordagem padrão .
Stéphane Chazelas

6

Use sedpara isso como mostrado abaixo:

SHW@SHW:/tmp $ cat a
this is line one
and this is line two
the third and the
fourth must be pasted too

SHW@SHW:/tmp $ sed 'N;s/\n/ /' a -i

SHW@SHW:/tmp $ cat a
this is line one and this is line two
the third and the fourth must be pasted too

4

Outra maneira é usar xargs:

$ < txt xargs -d '\n' -n 2 echo
this is line one and this is line two
the third and the fourth must be pasted too

Onde

$ cat txt
this is line one
and this is line two
the third and the
fourth must be pasted too

Embora essa solução seja bastante excessiva porque um echoprocesso é executado para cada linha ... Portanto, além dos exemplos de brinquedos, uma solução baseada em awk / sed ou similar deve ser preferida.


11
Dependendo da sua echoimplementação, você também terá problemas com caracteres de barra invertida ou algumas linhas que começam com -(como --helpou -nenecom o GNU echo). Observe também que -dé uma extensão GNU.
Stéphane Chazelas

Para evitar problemas echo, você pode usar o seguinte:< txt xargs -d '\n' -n 2 printf -- '%s %s\n'
nyuszika7h

4

Na verdade, isso é extremamente simples no vim. Para unir todas as linhas, use o Jcomando e, em seguida, use o %normcomando para aplicá-lo a todas as linhas simultaneamente. Por exemplo

:%norm J<CR>

(Caso você não esteja familiarizado com o vim, <CR>apenas significa entrar)

Isso funciona mesmo para unir um número arbitrário de linhas. Por exemplo, unir a cada dez linhas seria

:%norm 9J<CR>

Se você não se sente à vontade com o vim e prefere usá-lo como uma ferramenta de linha de comando, em vez de um editor de texto interativo, você pode:

vim myfile -c '%norm J' -c 'wq'

O downvoter se importaria em explicar o que posso fazer para melhorar esta resposta?
DJMcMayhem

3
$ awk '{printf "%s%s",$0,(NR%2?" ":"\n")}' sample.txt
this is line one and this is line two
the third and the fourth must be pasted too

Isso imprime cada linha, $0seguida por um espaço ou uma nova linha, dependendo do número da linha NR, ser ímpar ou par.

A expressão NR%2?" ":"\n"é uma declaração ternária. A expressão é NR%2avaliada como verdadeira (diferente de zero) se o número da linha for ímpar. No caso, a expressão ternária retorna um espaço. Se for avaliado como falso (zero), a nova linha será retornada.

Alternativo

Como sugerido por Costas nos comentários:

$ awk '{ORS=(NR%2?" ":RS)}1' sample.txt
this is line one and this is line two
the third and the fourth must be pasted too

Aqui, a instrução ternária NR%2?" ":RSé usada para retornar um espaço ou o separador de registro de entrada ( RS, padrão = nova linha). Este valor é atribuído ao separador de registros de saída ORS,. O 1final do comando é a abreviação enigmática do awk para imprimir o registro.


Você pode ainda salvar 3 personagens: os ()parênteses e o espaço depois printf;)
maxschlepzig

11
Ternário? Oh! 'NR%2{printf("%s ",$0);next}1'
Costas

Com a resposta de maxschlepzig e a declaração ternária:'{ORS=(NR%2?" ":RS)}1'
Costas

@ Costas eu gosto disso. Resposta atualizada com ORSsolução.
precisa saber é o seguinte

2

Solução genérica, substitua 5pelo número de linhas necessárias

$ # eof to ensure last line has newline ending
$ seq 16 | perl -pe 's/\n/ / if ++$i%5 && !eof'
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16

$ # or just use pr
$ seq 16 | pr -5ats' '
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16

1

Você pode usar awkpara isso:

$ awk '{c="\n"} NR%2 {c=" "} { printf("%s%s", $0, c) } ' txt

Produz:

this is line one and this is line two
the third and the fourth must be pasted too

Onde:

$ cat txt
this is line one
and this is line two
the third and the
fourth must be pasted too

As awkações são executadas para cada linha, a variável especial $0referencia a linha atual, NRé o número da linha atual (começando em 1). A segunda ação é protegida pela expressão NR%2, que é a operação do módulo. Assim, c=" "só é executado se NR%2for verdadeiro, ou seja, para números de linhas ímpares.

A awksintaxe é semelhante a C, mas alguns elementos são opcionais em alguns contextos - por exemplo, ponto e vírgula.


Sua cvariável é ORS:'NR%2{ORS=" "}1;{ORS=RS}'
Costas

0

Usando ed:

$ cat text
this is line one
and this is line two
the third and the
fourth must be pasted too
this is line one
and this is line two
the third and the
fourth must be pasted too

$ ed text <<'END_ED'
g/./s/$/ /\
j
w text.new
END_ED
164
164

$ cat text.new
this is line one and this is line two
the third and the fourth must be pasted too
this is line one and this is line two
the third and the fourth must be pasted too

Os edcomandos de edição, para cada linha ( gaplica um conjunto de comandos de edição a todas as linhas correspondentes à expressão regular especificada), adicionam um caractere de espaço ao final e o associam à próxima linha. Em seguida, ele grava o texto resultante em um arquivo chamado text.new.


0

Com Ruby.

Presumo que cada bloco de nlinhas deve ser unido. Suponha que n = 3o arquivo de entrada seja 'infile'e os resultados sejam gravados no arquivo 'outfile'.

Construir um arquivo

Ruby -e "File.write 'infile', <<_
> Line 1
> Line 2
> Line 3
> Line 4
> Line 5
> Line 6
> Line 7
> _"

Confirme o conteúdo do arquivo

ruby -e "p File.read 'infile'"
  # "Line 1\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\n"

Remova novas linhas e grave no arquivo

ruby -e "File.write 'outfile', File.readlines('infile').
  each_with_index { |line,i| line.chomp! unless (i+1)%3==0 }"

Confirmar conteúdo

ruby -e "puts File.read 'outfile'"
  # ["Line 1", "Line 2", "Line 3\n", "Line 4", "Line 5", "Line 6\n", "Line 7"]

11
Um bom. Em teoria, rubyé off-topic sobre U&L. Mas, como você o está usando na linha de comando ruby -e, isso o torna bastante tópico.
grochmal
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.