Supprimer le caractère de nouvelle ligne uniquement toutes les N lignes


16

Traitement du texte, je dois supprimer le caractère de nouvelle ligne toutes les deux lignes.

Exemple de texte:

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

Sortie désirée:

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

J'ai essayé une whileboucle, mais une boucle while est une mauvaise pratique. Est-il possible de le faire en utilisant trou toute autre commande?


4
Le titre dit "toutes les N lignes", mais dans la question et l'exemple c'est "toutes les 2 lignes". La plupart des réponses ne fonctionnent que pour N = 2. Cherchez-vous quelque chose qui fonctionne pour tous les N?
JigglyNaga

Voilà la clé. Tout le monde a répondu pour 2 lignes mais j'aurais besoin d'utiliser N = 3 ou N = 4
jomaweb

Réponses:


24

paste(également un utilitaire standard POSIX simple comme tr) est votre outil pour cela.

En supposant que vous souhaitiez que ces caractères de nouvelle ligne soient remplacés par un espace au lieu d'être simplement supprimés comme dans votre exemple:

paste -d ' ' - - < file

Ou:

paste -sd ' \n' file

Remplacez-le ' 'par '\0'si vous souhaitez vraiment les supprimer.

Pour remplacer 2 sur 3:

paste -sd '  \n' file

1 sur 3, en commençant par le second:

paste -sd '\n \n' file

Etc.

Une autre bonne chose pasteest qu'elle ne laissera pas de ligne non terminée. Par exemple, si vous supprimez chaque nouvelle ligne dans un fichier (comme avec tr -d '\n' < fileou tr '\n' ' ' < file), vous vous retrouvez sans ligne du tout car les lignes doivent se terminer par un caractère de nouvelle ligne. Il est donc généralement préférable d'utiliser à la pasteplace pour cela (comme dans paste -sd '\0' fileou paste -sd ' ' file) qui ajoutera le caractère de fin de ligne nécessaire pour avoir un texte valide.


11

Avec GNU sed moderne

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

Et awk

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

3
Cette sedapproche signifie slurper tout le fichier en mémoire (à condition qu'il ne contienne pas d'octets NUL) et faire une substitution coûteuse d'expressions rationnelles. Je ne vois pas l'avantage sur l' sed 'N;s/\n/ /'approche standard .
Stéphane Chazelas

6

Utilisez sedpour cela comme indiqué ci-dessous:

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

Une autre façon consiste à utiliser 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

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

Bien que cette solution soit assez excessive car un echoprocessus est exécuté pour chaque ligne ... Ainsi, en plus des exemples de jouets, une solution basée sur awk / sed ou similaire devrait être préférée.


1
Selon votre echoimplémentation, vous aurez également des problèmes avec les barres obliques inverses ou certaines lignes commençant par -(comme --helpou -neneavec GNU echo). Notez également qu'il -ds'agit d'une extension GNU.
Stéphane Chazelas

Pour éviter les problèmes avec echo, vous pouvez utiliser ceci:< txt xargs -d '\n' -n 2 printf -- '%s %s\n'
nyuszika7h

4

C'est en fait extrêmement simple dans vim. Pour joindre chaque ligne, utilisez la Jcommande, puis utilisez la %normcommande pour l'appliquer simultanément à chaque ligne. Par exemple

:%norm J<CR>

(Juste au cas où vous n'êtes pas familier avec vim, <CR>signifie simplement entrer)

Cela fonctionne même pour joindre un nombre arbitraire de lignes. Par exemple, joindre toutes les dix lignes serait

:%norm 9J<CR>

Si vous n'êtes pas à l'aise avec vim et que vous préférez l'utiliser comme outil de ligne de commande plutôt que comme éditeur de texte interactif, vous pouvez faire:

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

Est-ce que l'électeur se soucierait d'expliquer ce que je peux faire pour améliorer cette réponse?
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

Cela imprime chaque ligne, $0suivie d'un espace ou d'une nouvelle ligne selon que le numéro de ligne NR, est impair ou pair.

L'expression NR%2?" ":"\n"est une déclaration ternaire. L'expression est NR%2évaluée à vrai (différent de zéro) si le numéro de ligne est impair. Dans le cas, l'expression ternaire renvoie un espace. S'il est évalué à faux (zéro), la nouvelle ligne est renvoyée.

Alternative

Comme suggéré par Costas dans les commentaires:

$ 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

Ici, l'instruction ternaire NR%2?" ":RSest utilisée pour renvoyer soit un espace, soit le séparateur d'enregistrement en entrée ( RS, par défaut = nouvelle ligne). Cette valeur est affectée au séparateur de fiche de sortie, ORS. Le 1à la fin de la commande est le raccourci cryptique d'awk pour imprimer l'enregistrement.


Vous pouvez toujours enregistrer 3 caractères: les ()parenthèses et l'espace après printf;)
maxschlepzig

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

Avec la réponse et la déclaration ternaire de maxschlepzig :'{ORS=(NR%2?" ":RS)}1'
Costas

@Costas J'aime ça. Réponse mise à jour avec la ORSsolution.
John1024

2

Solution générique, remplacer 5par le nombre de lignes requises

$ # 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

Vous pouvez utiliser awkpour cela:

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

Cela produit:

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

où:

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

Les awkactions sont exécutées pour chaque ligne, la variable spéciale fait $0référence à la ligne courante, NRest le numéro de la ligne courante (commençant à 1). La deuxième action est gardée par l'expression NR%2, qui est l'opération modulo. Ainsi, il c=" "n'est exécuté que s'il NR%2est vrai, c'est-à-dire pour les numéros de ligne impairs.

La awksyntaxe est de type C, mais certains éléments sont facultatifs dans certains contextes - par exemple les points-virgules.


Votre cvariable est ORS:'NR%2{ORS=" "}1;{ORS=RS}'
Costas

0

En utilisant 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

Les edcommandes d'édition vont, pour chaque ligne ( gapplique un ensemble de commandes d'édition à chaque ligne correspondant à l'expression régulière donnée), ajouter un caractère espace à la fin et le joindre à la ligne suivante. Il écrit ensuite le texte résultant dans un fichier appelé text.new.


0

Avec Ruby.

Je suppose que chaque bloc de nlignes doit être joint. Supposons que n = 3le fichier d'entrée soit 'infile'et que les résultats soient écrits dans le fichier 'outfile'.

Construire un fichier

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

Confirmer le contenu du fichier

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

Supprimer les retours à la ligne et écrire dans le fichier

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

Confirmer le contenu

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

1
Bon. En théorie, rubyest hors sujet sur U&L. Mais, puisque vous l'utilisez à partir de la ligne de commande avec ruby -e, cela le rend suffisamment sur le sujet.
grochmal
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.