Remplacer la string contenant newline dans un file énorme

Quelqu'un sait-il d'un outil non-ligne à "binary" searchr / replace des cordes d'une manière peu efficace de memory? Voir cette question aussi.

J'ai un file text + 2GB que je voudrais traiter similaire à ce que cela semble faire:

sed -e 's/>\n/>/g' 

Cela signifie que je veux supprimer tous les returns qui se produisent après un > , mais pas n'importe où, de sorte que les règles tr -d .

Cette command (que j'ai obtenu de la réponse d'une question similaire ) échoue avec couldn't re-allocate memory :

 sed --unbuffered ':a;N;$!ba;s/>\n/>/g' 

Alors, y a-t-il d'autres methods sans recourir à C? Je déteste Perl, mais je suis prêt à faire une exception dans ce cas 🙂

Je ne sais pas avec certitude de caractère qui ne se trouve pas dans datatables, donc replace temporairement \n par un autre personnage est quelque chose que j'aimerais éviter si possible.

De bonnes idées, n'importe qui?

C'est vraiment sortingvial en Perl, tu ne devrais pas le détester!

 perl -i.bak -pe 's/>\n/>/' file 

Explication

  • -i : modifie le file en place et crée une sauvegarde de l'original appelé file.bak . Si vous ne voulez pas de sauvegarde, utilisez plutôt perl -i -pe .
  • -pe : lit le file d'input ligne par ligne et imprime chaque ligne après avoir appliqué le script donné en -e .
  • s/>\n/>/ : la substitution, tout comme sed .

Et voici une approche awk :

 awk '{if(/>$/){printf "%s",$0}else{print}}' file2 

Une solution perl :

 $ perl -pe 's/(?<=>)\n//' 

Explication

  • s/// est utilisé pour la substitution de string.
  • (?<=>) est lookbehind pattern.
  • \n correspond à newline.

Le motif entier signifiant enlever toutes les lignes qui ont > avant cela.

Que dis-tu de ça:

 sed ':loop />$/ { N s/\n// b loop }' file 

Pour GNU sed, vous pouvez également essayer d'append l'option -u ( --unbuffered ) selon la question. GNU sed est également heureux avec ceci comme un simple doubleur:

 sed ':loop />$/ { N; s/\n//; b loop }' file 

Vous devriez être capable d'utiliser sed avec la command N , mais l'astuce consiste à supprimer une ligne de l'espace du motif chaque fois que vous en ajoutez une autre (afin que l'espace du motif ne contienne toujours que 2 lignes consécutives au lieu d'essayer de lire le file entier) – essayez

 sed ':a;$!N;s/>\n/>/;P;D;ba' 

EDIT: après avoir relu le célèbre Sed One-Liners de Peteris Krumins, je crois qu'une meilleure solution sed serait

 sed -e :a -e '/>$/N; s/\n//; ta' 

qui ajoute seulement la ligne suivante dans le cas où il est déjà fait une > correspondance à la fin, et devrait boucler conditionnellement pour traiter le cas des lignes correspondantes consécutives (c'est le 39 de Krumin . Ajoutez une ligne à la suivante si elle se termine par un backslash "\" exactement à l'exception de la substitution de > par \ comme caractère de jointure et du fait que le caractère de jointure est conservé dans la sortie).

sed ne permet pas d'émettre des résultats sans une nouvelle ligne finale. Votre approche utilisant N fonctionne fondamentalement, mais stocke des lignes incomplètes dans la memory, et peut donc échouer si les lignes deviennent trop longues (les implémentations sed ne sont généralement pas conçues pour gérer des lignes extrêmement longues).

Vous pouvez utiliser awk à la place.

 awk '{if (/<$/) printf "%s", $0; else print}' 

Une autre approche consiste à utiliser tr pour permuter le caractère de nouvelle ligne avec un caractère "ennuyeux", qui se produit fréquemment. L'espace peut fonctionner ici – choisissez un personnage qui a tendance à apparaître sur chaque ligne ou au less une grande proportion de lignes dans vos données.

 tr ' \n' '\n ' | sed 's/> />/g' | tr '\n ' ' \n' 

que diriez-vous d'utiliser ed?

 ed -s test.txt <<< $'/fruits/s/apple/banana/g\nw' 

(via http://wiki.bash-hackers.org/howto/edit-ed )

J'ai fini par utiliser gsar comme décrit dans cette réponse comme ceci:

 gsar -F '-s>:x0A' '-r>' 

Il y a beaucoup de façons de le faire, et la plupart ici sont vraiment bons, mais je pense que celui-ci est mon préféré:

 tr '>\n' '\n>' | sed 's/^>*//;H;/./!d;x;y/\n>/>\n/' 

Ou même:

 tr '>\n' '\n>' | sed 's/^>*//' | tr '\n>' '>\n'