J'ai des fichiers qui se terminent par un ou plusieurs sauts de ligne et doivent se terminer par un seul saut de ligne. Comment puis-je faire cela avec les outils Bash / Unix / GNU?
Exemple de mauvais fichier:
1\n
\n
2\n
\n
\n
3\n
\n
\n
\n
Exemple de fichier corrigé:
1\n
\n
2\n
\n
\n
3\n
En d'autres termes: il doit y avoir exactement une nouvelle ligne entre l'EOF et le dernier caractère non nouvelle ligne du fichier.
Implémentation de référence
Lisez le contenu du fichier, coupez une seule nouvelle ligne jusqu'à ce qu'il n'y ait plus deux nouvelles lignes à la fin, réécrivez-la:
#! /bin/python
import sys
with open(sys.argv[1]) as infile:
lines = infile.read()
while lines.endswith("\n\n"):
lines = lines[:-1]
with open(sys.argv[2], 'w') as outfile:
for line in lines:
outfile.write(line)
Clarification: Bien sûr, la tuyauterie est autorisée, si c'est plus élégant.
sed
proposition, je pensais juste OMG ...awk: illegal statement
.brew install mawk
et changer la commande enmawk
fonctionne cependant.À partir de scripts d'une ligne utiles pour sed .
la source
find . -type f -name '*.js' -exec sed --in-place -e :a -e '/^\n*$/{$d;N;};/\n$/ba' {} \;
find . -type f -name '*.js' -exec sed -i '' -e :a -e '/^\n*$/{$d;N;};/\n$/ba' {} \;
Puisque vous avez déjà des réponses avec les outils les plus adaptés sed et awk; vous pouvez profiter du fait que les
$(< file)
bandes vides de fin sont supprimées.Ce hack bon marché ne fonctionnerait pas pour supprimer les lignes vides de fin qui peuvent contenir des espaces ou d'autres caractères non imprimables, uniquement pour supprimer les lignes vides de fin. Cela ne fonctionnera pas non plus si le fichier contient des octets nuls.
Dans les shells autres que bash et zsh, utilisez
$(cat file)
plutôt que$(<file)
.la source
$()
supprime les nouvelles lignes de fin. C'est une décision de conception. Je suppose que cela facilitera l'intégration dans d'autres chaînes: ceecho "On $(date ...) we will meet."
serait mal avec la nouvelle ligne que presque toutes les commandes shell produisent à la fin.[[ $a == '' ]] || printf '%s\n' "$a" >"$file"
.a=$(gtac file.txt); printf '%s\n' "$a" | gtac > file.txt
Vous pouvez utiliser cette astuce avec
cat
&printf
:Par exemple
Le
$
dénote la fin d'une ligne.Les références
la source
Cette question est étiquetée avec ed , mais personne n'a proposé de
ed
solution.En voici un:
ou équivalent,
ed
vous placera par défaut à la dernière ligne du tampon d'édition au démarrage.La première commande (
a
) ajoute une ligne vide à la fin du tampon (la ligne vide dans le script d'édition est cette ligne, et le point (.
) est juste pour revenir en mode commande).La deuxième commande (
?
) recherche la ligne précédente la plus proche contenant quelque chose (même des espaces blancs), puis supprime tout à la fin du tampon de la ligne suivante.La troisième commande (
w
) réécrit le fichier sur le disque.La ligne vide ajoutée protège le reste du fichier contre la suppression dans le cas où il n'y a pas de lignes vides à la fin du fichier d'origine.
la source
Voici une solution Perl qui ne nécessite pas de lire plus d'une ligne en mémoire à la fois:
ou, en une ligne:
Cela lit le fichier une ligne à la fois et vérifie chaque ligne pour voir si contient un caractère non-newline. Si ce n'est pas le cas, il incrémente un compteur; si c'est le cas, il imprime le nombre de nouvelles lignes indiqué par le compteur, suivi de la ligne elle-même, puis réinitialise le compteur.
Techniquement, même la mise en mémoire tampon d'une seule ligne en mémoire n'est pas nécessaire; il serait possible de résoudre ce problème en utilisant une quantité constante de mémoire en lisant le fichier en morceaux de longueur fixe et en le traitant caractère par caractère à l'aide d'une machine à états. Cependant, je soupçonne que ce serait inutilement compliqué pour le cas d'utilisation typique.
la source
Si votre fichier est suffisamment petit pour glisser en mémoire, vous pouvez utiliser ce
la source
En python (je sais que ce n'est pas ce que vous voulez, mais c'est beaucoup mieux car il est optimisé, et un prélude à la version bash) sans réécrire le fichier et sans lire tout le fichier (ce qui est une bonne chose si le fichier est très grand):
Notez qu'il ne fonctionne pas sur les fichiers où le caractère EOL n'est pas '\ n'.
la source
Une version bash, implémentant l'algorithme python, mais moins efficace car elle nécessite de nombreux processus:
la source
Celui-ci est rapide à taper et, si vous connaissez sed, facile à retenir:
Il utilise le script sed pour supprimer les premières lignes vides des scripts d'une ligne utiles pour sed , référencés par Alexey, ci-dessus, et tac (reverse cat).
Dans un test rapide, sur un fichier de 18 Mo, 64 000 lignes, l'approche d'Alexey était plus rapide (0,036 contre 0,046 seconde).
la source