web-dev-qa-db-fra.com

Ajouter une nouvelle ligne uniquement si elle n'existe pas

Je souhaite ajouter une nouvelle ligne à la fin d'un fichier uniquement s'il n'existe pas, afin d'éviter plusieurs nouvelles lignes à la fin du fichier.

J'espère utiliser sed. Voici les problèmes que je rencontre avec mon code actuel:

sed -i -e '/^$/d;$G' /inputfile

echo file1
name1
name2

echo file2
name3
name4
(newline)

quand je lance mon code sur les fichiers;

echo file1
name1
name2
(newline)

echo file2
name3
name4

il ajoute une nouvelle ligne si elle n’a pas mais supprime s’il existe ... cela me surprend ..

31
AlwynIsPat

Puisqu'il supprime newline s'il n'est pas là, vous pouvez simplement utiliser:

echo "" >> file;  sed -ie '/^$/d;$G' file; sed -ie '/^$/d;$G' file

Ajoute une nouvelle ligne et supprime tout, puis ajoute une nouvelle ligne. Pas la manière élégante, mais fonctionne certainement :)

5
P.P.

sed

GNOU:

sed -i '$a\' *.txt

OS X:

sed -i '' '$a\' *.txt

$ adresse la dernière ligne. a\ est la fonction append.

OS X's sed

sed -i '' -n p *.txt

-n désactive l'impression et p imprime l'espace du motif. p ajoute une nouvelle ligne manquante dans le fichier sed de OS X mais pas dans GNU sed, de sorte que cela ne fonctionne pas avec GNU sed.

awk

awk 1

1 peut être remplacé par tout ce qui est évalué à true. Modifier un fichier en place:

{ rm file;awk 1 >file; }<file

bash

[[ $(tail -c1 file) && -f file ]]&&echo ''>>file

Les nouvelles lignes de fin sont supprimées du résultat de la substitution de commande. Par conséquent, $(tail -c1 file) est vide uniquement si file se termine par un saut de ligne ou est vide. -f file est false si file est vide. [[ $x ]] est équivalent à [[ -n $x ]] en bash.

33
Lri

Plutôt que de traiter le fichier entier avec see juste pour ajouter une nouvelle ligne à la fin, vérifiez simplement le dernier caractère et si c'est pas une nouvelle ligne, ajoutez-en un. Tester la nouvelle ligne est légèrement intéressant, car le Shell les coupera généralement à la fin des chaînes. J'ajoute donc "x" pour le protéger:

if [ "$(tail -c1 "$inputfile"; echo x)" != $'\nx' ]; then
    echo "" >>"$inputfile"
fi

Notez que cela ajoutera newline aux fichiers vides, ce qui pourrait ne pas être ce que vous voulez. Si vous voulez laisser les fichiers vides seuls, ajoutez un autre test:

if [ -s "$inputfile" ] && [ "$(tail -c1 "$inputfile"; echo x)" != $'\nx' ]; then
    echo "" >>"$inputfile"
fi
7
Gordon Davisson

Utilisation de awk:

awk '/^$/{f=1}END{ if (!f) {print "\r"}}1' inputfile

Faites correspondre la ligne vierge ^$ (comme vous l'avez fait) et configurez un drapeau. Si flag n'est pas défini à la fin, placez le caractère de nouvelle ligne.

Remarque: ce \r est sous OS X. Utilisez \n pour autre.

2
ring bearer
tail -c1 file | read -r _ || echo >> file

récupère le dernier caractère du fichier dans read, qui se terminera par un code de sortie différent de zéro s'il rencontre EOF avant la nouvelle ligne (ainsi, si le dernier caractère du fichier n'est pas une nouvelle ligne). Si read quitte nonzero, ajoutez une nouvelle ligne au fichier à l'aide de echo (si read quitte 0, cela satisfait le ||, de sorte que la commande echo n'est pas exécutée).

De http://backreference.org/2010/05/23/sanitizing-files-with-no-trailing-newline/ .

1
Isaac

Essayez d'utiliser vi ou ex:

ex -scwq foo.txt

ou pour plusieurs fichiers:

vi -es +"bufdo wq" *.txt
ex -s +"bufdo wq" *.txt

qui ajoute automatiquement EOL à EOF lors de la sauvegarde du fichier s'il est manquant.

Pour appliquer de manière récursive certains fichiers, utilisez une nouvelle option de remplacement (**) telle que **/*.txt (activée par shopt -s globstar).

0
kenorb

Utilisation de Bash uniquement

Vous pouvez utiliser Substitution de commande (supprimer les nouvelles lignes de fin) avec Here Strings (ajoute une nouvelle ligne):

   Command Substitution
       Command substitution allows the output of a command to replace the command  name.   There  are  two
       forms:

          $(command)
       or
          `command`

       Bash  performs  the expansion by executing command in a subshell environment and replacing the com-
       mand substitution with the standard output of the command,  with  any  trailing  newlines  deleted.
       Embedded newlines are not deleted, but they may be removed during Word splitting.  The command sub-
       stitution $(cat file) can be replaced by the equivalent but faster $(< file).



   Here Strings
       A variant of here documents, the format is:

          [n]<<<Word

       The Word undergoes brace expansion, tilde expansion, parameter and variable expansion, command sub-
       stitution,  arithmetic expansion, and quote removal.  Pathname expansion and Word splitting are not
       performed.  The result is supplied as a single string, with a newline appended, to the  command  on
       its standard input (or file descriptor n if n is specified).

Voici comment ça fonctionne:

cat <<<"$(<inputfile)"

Sortie dans un fichier:

cat <<<"$(<inputfile)" >outputfile

Si vous souhaitez que inputfile et outputfile soient identiques, vous avez le choix entre plusieurs options: utiliser la commande sponge, enregistrer dans une variable temporaire avec davantage de substitution de commande ou enregistrer dans un fichier temporaire.


Utilisation de Sed

D'autres ont suggéré d'utiliser

sed '$a\' inputfile

qui n'ajoute rien à la dernière ligne. C'est bien, mais je pense

sed '$q' inputfile

est un peu plus clair, car il se ferme sur la dernière ligne. Ou tu peux faire

sed -n 'p'

qui utilise -n pour supprimer la sortie, mais l’imprime avec p.

Dans tous les cas, sed corrige la ligne et ajoute une nouvelle ligne, au moins pour GNU et BSD sed. Cependant, je ne suis pas sûr que cette fonctionnalité soit définie par POSIX. Une version de sed peut simplement ignorer votre ligne sans nouvelle ligne car une ligne est définie comme

Une séquence de zéro ou plusieurs non-caractères plus un caractère de fin.

0
dosentmatter

J'ai résolu cette tâche en utilisant dos2unix (ou ses homologues) avec l'indicateur --newline. L'avantage est que ces outils détectent eux-mêmes les fichiers binaires. J'aime la solution avec tail -c1 mais filtrer au préalable les fichiers binaires a été vraiment lent pour moi.

dos2unix --newline my_file.txt

Finalement, j'ai écrit un script qui cherchait dans le répertoire de mon projet, convertissait tous les fichiers en LF (dos2unix) à l'exception de *.cmd fichiers (CRLF, unix2dos) et utilisais l'indicateur pour obtenir les nouvelles lignes d'un appel.

0
Daniel Böhmer