J'ai quelques fichiers que j'aimerais supprimer le dernier saut de ligne s'il s'agit du dernier caractère d'un fichier. od -c
me montre que la commande que j'exécute écrit le fichier avec une nouvelle ligne à la fin:
0013600 n t > \n
J'ai essayé quelques trucs avec sed, mais le mieux auquel je puisse penser ne fait pas l'affaire:
sed -e '$s/\(.*\)\n$/\1/' abc
Des idees pour faire cela?
\n
, dans Linux, il y a un caractèreRéponses:
ou, pour éditer le fichier sur place:
[Note de l'éditeur:
-pi -e
c'était à l'origine-pie
, mais, comme l'ont noté plusieurs commentateurs et expliqué par @hvd, ce dernier ne fonctionne pas.]Cela a été décrit comme un «blasphème perl» sur le site awk que j'ai vu.
Mais, dans un test, cela a fonctionné.
la source
chomp
. Et cela vaut la peine de glisser le fichier.perl -pi -e 'chomp if eof' filename
, pour éditer un fichier sur place au lieu de créer un fichier temporaireperl -pie 'chomp if eof' filename
-> Impossible d'ouvrir le script perl "chomp if eof": aucun fichier ou répertoire de ce type;perl -pi -e 'chomp if eof' filename
-> fonctionneVous pouvez profiter du fait que les substitutions de commandes shell suppriment les caractères de fin de ligne :
Formulaire simple qui fonctionne dans bash, ksh, zsh:
Alternative portable (compatible POSIX) (légèrement moins efficace):
Remarque:
in.txt
extrémités avec plusieurs caractères de nouvelle ligne, la substitution de commande supprime tous d'entre eux - grâce, @Sparhawk. (Il ne supprime pas les caractères d'espacement autres que les retours à la ligne de fin.)printf %s
garantit qu'aucune nouvelle ligne n'est ajoutée à la sortie (c'est l'alternative compatible POSIX au non standardecho -n
; voir http://pubs.opengroup.org/onlinepubs/009696799/utilities/echo.html et https: //unix.stackexchange. com / a / 65819 )Un guide des autres réponses :
Si Perl est disponible, choisissez la réponse acceptée - elle est simple et économe en mémoire (ne lit pas tout le fichier d'entrée à la fois).
Sinon, considérez la réponse Awk de ghostdog74 - elle est obscure, mais aussi efficace en mémoire ; un équivalent plus lisible (compatible POSIX) est:
awk 'NR > 1 { print prev } { prev=$0 } END { ORS=""; print }' in.txt
END
bloc, où elle est imprimée sans fin en\n
raison de la définition du séparateur d'enregistrement de sortie (OFS
) sur une chaîne vide.Si vous voulez une solution détaillée, mais rapide et robuste qui modifie réellement sur place (par opposition à la création d'un fichier temporaire qui remplace ensuite l'original), considérez le script Perl de jrockway .
la source
Vous pouvez le faire avec
head
depuis GNU coreutils, il prend en charge les arguments relatifs à la fin du fichier. Donc, pour ne pas utiliser le dernier octet:Pour tester une nouvelle ligne de fin, vous pouvez utiliser
tail
etwc
. L'exemple suivant enregistre le résultat dans un fichier temporaire et remplace par la suite l'original:Vous pouvez également utiliser
sponge
frommoreutils
pour effectuer des modifications "sur place":Vous pouvez également créer une fonction réutilisable générale en insérant ceci dans votre
.bashrc
fichier:Mettre à jour
Comme indiqué par KarlWilbur dans les commentaires et utilisé dans la réponse de Sorentar ,
truncate --size=-1
peut remplacerhead -c-1
et prend en charge l'édition sur place.la source
truncate --size=-1
au lieu dehead -c -1
car il redimensionne simplement le fichier d'entrée plutôt que de lire le fichier d'entrée, de l'écrire dans un autre fichier, puis de remplacer l'original par le fichier de sortie.head -c -1
cela supprimera le dernier caractère, qu'il s'agisse d'une nouvelle ligne ou non, c'est pourquoi vous devez vérifier si le dernier caractère est une nouvelle ligne avant de le supprimer.Modifier 2:Voici uneawk
version (corrigée) qui n'accumule pas un tableau potentiellement énorme:awk '{if (line) print line; ligne = $ 0} END {printf $ 0} 'abcla source
awk
version. Il faut deux décalages (et un test différent) et je n'en ai utilisé qu'un. Cependant, vous pouvez utiliser à laprintf
place deORS
.head -n -1 abc | cat <(tail -n 1 abc | tr -d '\n') | ...
rester bouche bée
la source
awk '{ prev_line = line; line = $0; } NR > 1 { print prev_line; } END { ORS = ""; print line; }' file
cela devrait être plus facile à lire.awk 'NR>1 {print p} {p=$0} END {printf $0}' file
.printf
est l' argument format . Ainsi, si le fichier d'entrée avait quelque chose qui pourrait être interprété comme un spécificateur de format comme%d
, vous obtiendrez une erreur. Une solution serait de le changer enprintf "%s" $0
Une méthode très simple pour les fichiers sur une seule ligne, nécessitant l'écho GNU de coreutils:
la source
\n
est présent. Au fur et à mesure qu'il est converti en une nouvelle ligne.$(...)
est cité/bin/echo -n "$(cat infile)"
Je dois absolument le citer ... De plus, je ne suis pas sûr de la longueur maximaleecho
ou du shell dans les versions / distributions d'os / shell (je cherchais juste ceci et c'était un trou de lapin), alors je suis Je ne sais pas à quel point il serait portable (ou performant) pour autre chose que les petits fichiers - mais pour les petits fichiers, super.Si vous voulez bien faire les choses, vous avez besoin de quelque chose comme ceci:
Nous ouvrons le fichier pour lecture et ajout; l'ouverture pour l'ajout signifie que nous sommes déjà
seek
à la fin du fichier. On obtient alors la position numérique de la fin du fichier avectell
. Nous utilisons ce nombre pour rechercher un caractère, puis nous lisons ce caractère. S'il s'agit d'une nouvelle ligne, nous tronquons le fichier au caractère avant cette nouvelle ligne, sinon nous ne faisons rien.Cela fonctionne en temps constant et en espace constant pour n'importe quelle entrée, et ne nécessite pas non plus d'espace disque.
la source
Voici une solution Python sympa et bien rangée. Je n'ai pas essayé d'être laconique ici.
Cela modifie le fichier sur place, plutôt que de faire une copie du fichier et de supprimer la nouvelle ligne de la dernière ligne de la copie. Si le fichier est volumineux, ce sera beaucoup plus rapide que la solution Perl qui a été choisie comme meilleure réponse.
Il tronque un fichier de deux octets si les deux derniers octets sont CR / LF, ou d'un octet si le dernier octet est LF. Il n'essaye pas de modifier le fichier si le ou les derniers octets ne sont pas (CR) LF. Il gère les erreurs. Testé en Python 2.6.
Mettez ceci dans un fichier appelé "striplast" et
chmod +x striplast
.PS Dans l'esprit du "Perl golf", voici ma solution Python la plus courte. Il extrait le fichier entier de l'entrée standard dans la mémoire, supprime toutes les nouvelles lignes à la fin et écrit le résultat sur la sortie standard. Pas aussi laconique que le Perl; vous ne pouvez pas battre Perl pour de petits trucs rapides et délicats comme celui-ci.
Supprimez le "\ n" de l'appel à
.rstrip()
et il supprimera tous les espaces blancs à la fin du fichier, y compris plusieurs lignes vides.Mettez ceci dans "slurp_and_chomp.py" puis exécutez
python slurp_and_chomp.py < inputfile > outputfile
.la source
Une solution rapide utilise l'utilitaire gnu
truncate
:Le test sera vrai si le fichier a une nouvelle ligne à la fin.
La suppression est très rapide, vraiment en place, aucun nouveau fichier n'est nécessaire et la recherche lit également à la fin un seul octet (
tail -c1
).la source
[ -z $(tail -c1 filename) ] && truncate -s -1 filename
(aussi, en réponse à l'autre commentaire, latruncate
commande ne fonctionne pas avec stdin, un nom de fichier est requis)Encore un autre WTDI perl:
la source
Voir aussi Faire correspondre n'importe quel caractère (y compris les sauts de ligne) dans sed .
la source
tr -d '\n'
Utilisation de dd:
la source
la source
g
ou les parenthèses autour deeof
:perl -pi -e 's/\n$// if eof' your_file
.En supposant le type de fichier Unix et que vous ne voulez que la dernière nouvelle ligne, cela fonctionne.
Cela ne fonctionnera pas sur plusieurs nouvelles lignes ...
* Fonctionne uniquement si la dernière ligne est une ligne vierge.
la source
sed
solution qui fonctionne même pour une dernière ligne non vierge: stackoverflow.com/a/52047796Encore une autre réponse FTR (et ma préférée!): Echo / cat la chose que vous voulez dépouiller et capturer la sortie par des backticks. La dernière nouvelle ligne sera supprimée. Par exemple:
la source
POSIX SED:
«$ {/ ^ $ / d}»
la source
echo -en 'a\nb\n' | sed '${/^$/d}'
ne supprimera rien.echo -en 'a\nb\n\n' | sed '${/^$/d}'
supprimera puisque toute la dernière ligne est vide.C'est une bonne solution si vous en avez besoin pour travailler avec des tubes / redirection au lieu de lire / sortir depuis ou vers un fichier. Cela fonctionne avec une ou plusieurs lignes. Cela fonctionne qu'il y ait une nouvelle ligne de fin ou non.
Détails:
head -c -1
tronque le dernier caractère de la chaîne, quel que soit le caractère. Donc, si la chaîne ne se termine pas par une nouvelle ligne, vous perdrez un caractère.sed '$s/$//'
. Le premier$
signifie n'appliquer la commande qu'à la dernière ligne.s/$//
signifie remplacer la «fin de la ligne» par «rien», ce qui ne fait essentiellement rien. Mais cela a pour effet secondaire d'ajouter une nouvelle ligne de fin s'il n'y en a pas.Remarque: la valeur par défaut de Mac
head
ne prend pas en charge l'-c
option. Vous pouvez fairebrew install coreutils
et utiliser à laghead
place.la source
La seule fois où j'ai voulu faire cela, c'est pour le code golf, puis j'ai simplement copié mon code hors du fichier et l'ai collé dans une
echo -n 'content'>file
instruction.la source
la source
J'ai eu un problème similaire, mais je travaillais avec un fichier Windows et j'ai besoin de conserver ces CRLF - ma solution sous Linux:
la source
Devrait supprimer toute dernière occurrence de \ n dans le fichier. Ne fonctionne pas sur un fichier énorme (en raison de la limitation du tampon sed)
la source
rubis:
ou:
la source