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 ..
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 :)
GNOU:
sed -i '$a\' *.txt
OS X:
sed -i '' '$a\' *.txt
$
adresse la dernière ligne. a\
est la fonction append.
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 1
1
peut être remplacé par tout ce qui est évalué à true. Modifier un fichier en place:
{ rm file;awk 1 >file; }<file
[[ $(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.
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
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.
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/ .
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
).
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.
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.