Y a-t-il un problème avec sed et le nouveau caractère de ligne?
J'ai un fichier test.txt avec le contenu suivant
aaaaa
bbbbb
ccccc
ddddd
Ce qui suit ne fonctionne pas:sed -r -i 's/\n/,/g' test.txt
Je sais que je peux utiliser tr
pour cela mais ma question est pourquoi cela ne semble pas possible avec sed.
S'il s'agit d'un effet secondaire du traitement du fichier ligne par ligne, j'aimerais savoir pourquoi cela se produit. Je pense que grep
supprime les nouvelles lignes. Sed fait-il de même?
Avec GNU sed
et fourni POSIXLY_CORRECT
n'est pas dans l'environnement (pour une entrée sur une seule ligne):
sed -i ':a;N;$!ba;s/\n/,/g' test.txt
De https://stackoverflow.com/questions/1251999/sed-how-can-i-replace-a-newline-n :
:a
N
$!ba
($!
signifie ne pas le faire sur la dernière ligne (car il devrait y avoir une dernière ligne finale)).Cela fonctionne avec GNU sed
:
sed -z 's/\n/,/g'
-z
est inclus depuis 4.2.2
NB. -z
change le délimiteur en caractères nuls (\0
). Si votre entrée ne contient aucun caractère nul, l'entrée entière est traitée comme une seule ligne. Cela peut venir avec ses limitations .
Pour éviter de remplacer la nouvelle ligne de la dernière ligne, vous pouvez la modifier à nouveau:
sed -z 's/\n/,/g;s/,$/\n/'
(Ce qui est à nouveau la syntaxe GNU sed
, mais cela n'a pas d'importance car le tout est GNU uniquement))
sed
supprime toujours la fin de ligne \n
juste avant de remplir l'espace de motif, puis en ajoute une avant d'écrire les résultats de son script. Une ligne électronique \n
Peut être utilisée dans l'espace de motifs de différentes manières - mais jamais si elle n'est pas le résultat d'une modification. Ceci est important - les lignes électroniques de \n
Dans l'espace modèle de sed
reflètent toujours un changement et ne se produisent jamais dans le flux d'entrée. \n
Les lignes électroniques sont le seul délimiteur sur lequel un sed
der peut compter avec une entrée inconnue.
Si vous souhaitez remplacer tous les ewlines \n
Par des virgules et que votre fichier n'est pas très volumineux, vous pouvez faire:
sed 'H;1h;$!d;x;y/\n/,/'
Cela ajoute chaque ligne d'entrée à h
old espace - sauf la première, qui remplace à la place h
old espace - à la suite d'un caractère de ligne électronique \n
. Ensuite, d
eletes chaque ligne et non le $!
Dernier de la sortie. Sur la dernière ligne, H
old et les espaces de motif sont e x
changé et tous les caractères de ligne $ \n
Sont y///
Traduits en virgules.
Pour les fichiers volumineux, ce genre de chose est susceptible de causer des problèmes - le tampon de sed
sur les limites de ligne, qui peut facilement être débordé avec des actions de ce type.
Depuis le site Web d'Oracle:
L'utilitaire sed fonctionne en lisant séquentiellement un fichier, ligne par ligne, dans la mémoire. Il effectue ensuite toutes les actions spécifiées pour la ligne et remet la ligne en mémoire pour la transférer vers le terminal avec les modifications demandées. Une fois que toutes les actions ont été effectuées sur cette seule ligne, il lit la ligne suivante du fichier et répète le processus jusqu'à ce qu'il soit terminé avec le fichier.
Fondamentalement, cela signifie que parce que sed lit ligne par ligne, le caractère de nouvelle ligne n'est pas mis en correspondance.
La solution de https://stackoverflow.com/questions/1251999/sed-how-can-i-replace-a-newline-n est:
sed ':a;N;$!ba;s/\n/,/g'
ou, dans une version portable (sans ;
concaténation après les étiquettes de marque de saut)
sed -e ':a' -e 'N;$!ba' -e 's/\n/,/g'
Une explication sur la façon dont cela fonctionne est fournie sur cette page.
Il y a en fait deux questions sur votre message:
Sed peut-il remplacer les nouveaux caractères de ligne?
Oui. Absolument oui. Tout sed pourrait faire:
s/\n/,/g
ou
y/\n/,/
Cela transformera toute nouvelle ligne (qui est entrée dans l'espace de motif) en virgules.
Y a-t-il un problème avec sed et le nouveau caractère de ligne?
Oui, il y a plusieurs problèmes avec le caractère de nouvelle ligne dans sed:
Tous les points ci-dessus rendent difficile la "conversion de nouvelles lignes" en quelque chose.
Et, si les sauts de ligne sont remplacés par un autre caractère de texte, sed doit contenir le fichier texte entier en mémoire (quel que soit le processus utilisé pour y arriver).
Voici quelques solutions qui capturent l'intégralité du fichier en mémoire dans sed:
sed 'H;1h;$!d;x;y/\n/,/' file # most seds. [1]
sed ':a;N;$!ba;s/\n/,/g' file # GNU sed.
sed -z 's/\n/,/g;s/,$/\n/' file # GNU sed.
Voici quelques solutions rapides qui n'utilisent pas beaucoup de mémoire:
tr '\n' ',' file ; echo
awk '{printf("%s%s",NR==1?"":",",$0)}END{print ""}' file
1À partir des solutions sed: pour chaque ligne, H ajoute la ligne à l'espace d'attente (sauf que la première ligne remplace complètement l'espace d'attente (évitez une nouvelle ligne)), puis l'espace de motif est effacé par $!d
(sauf sur la dernière ligne). Sur cette dernière ligne, qui n'a pas été effacée, le reste des commandes est exécuté. Tout d'abord, récupérez toutes les lignes capturées dans l'espace d'attente avec x
, puis remplacez toutes les nouvelles lignes par une virgule avec y/\n/,/
.
Alternativement, vous pouvez utiliser une syntaxe légèrement plus simple:
sed ':a;N;s/\n/,/g;ba'
... juste changer l'ordre des séquences.
Il y a une très belle magie sed ici. Et quelques bons points soulevés au sujet du débordement de l'espace de motif. J'adore utiliser sed même quand ce n'est pas le moyen le plus simple, car il est si compact et puissant. Cependant, il a ses limites, et pour de grandes quantités de données, l'espace de modèle devrait être mahoosif.
GNU dit ceci:
Pour ceux qui souhaitent écrire des scripts sed portables, sachez que certaines implémentations sont connues pour limiter les longueurs de ligne (pour le modèle et les espaces d'attente) à pas plus de 4000 octets. La norme posix spécifie que les implémentations sed conformes doivent prendre en charge des longueurs de ligne d'au moins 8192 octets. GNU sed n'a pas de limite intégrée sur la longueur des lignes; tant qu'il peut malloc () plus de mémoire (virtuelle), vous pouvez alimenter ou construire des lignes aussi longtemps que vous le souhaitez.
Cependant, la récursivité est utilisée pour gérer les sous-modèles et la répétition indéfinie. Cela signifie que l'espace de pile disponible peut limiter la taille du tampon qui peut être traité par certains modèles.
Je n'ai pas grand-chose à ajouter, mais je voudrais vous diriger vers mon guide de référence pour sed . C'est excellent. http://www.grymoire.com/Unix/Sed.html
et voici ma solution:
for i in $(cat test.txt); do echo -n $i','; done; echo '' >> somewhere
ça marche
Supposons que vous souhaitiez remplacer les sauts de ligne par \n
. Je voulais le faire, alors voici ce que j'ai fait:
(echo foo; echo bar; echo baz) | sed -r '$!s/$/\\n/' | tr -d '\n'
# Output: foo\nbar\nbaz
Voici ce qu'il fait: pour toutes les lignes sauf la dernière, ajoutez \n
. Ensuite, supprimez les sauts de ligne avec tr
.