J'ai le scénario où des lignes doivent être ajoutées au début et à la fin des fichiers énormes.
J'ai essayé comme indiqué ci-dessous.
pour la première ligne:
sed -i '1i\'"$FirstLine" $Filename
pour la dernière ligne:
sed -i '$ a\'"$Lastline" $Filename
Mais le problème avec cette commande est qu'elle ajoute la première ligne du fichier et traverse le fichier entier. Pour la dernière ligne, il traverse à nouveau l'intégralité du fichier et ajoute une dernière ligne. Depuis son très gros fichier (14 Go), cela prend beaucoup de temps.
Comment puis-je ajouter une ligne au début et une autre à la fin d'un fichier en ne lisant le fichier qu'une seule fois?
la source
for
boucle:for file in Tes*; do [command]; done
"$file"
, pasTes*
comme argumented
.Notez que si vous voulez éviter d'allouer une copie entière du fichier sur le disque, vous pouvez faire:
Cela utilise le fait que lorsque son stdin / stdout est un fichier,
sed
lit et écrit par bloc. Donc ici, c'est OK pour qu'il écrase le fichier qu'il lit tant que la première ligne que vous ajoutez est plus petite quesed
la taille de bloc de (devrait être quelque chose comme 4k ou 8k).Notez cependant que si pour une raison quelconque
sed
échoue (tué, plantage de la machine ...), vous vous retrouverez avec le fichier à moitié traité, ce qui signifiera que certaines données de la taille de la première ligne manquent quelque part au milieu.Notez également qu'à moins que vous ne soyez
sed
le GNUsed
, cela ne fonctionnera pas pour les données binaires (mais puisque vous utilisez-i
, vous utilisez GNU sed).la source
Voici quelques choix (qui créeront tous une nouvelle copie du fichier, alors assurez-vous d'avoir suffisamment d'espace pour cela):
écho / chat simple
awk / gawk etc
awk
et ses autres fichiers de lecture ligne par ligne. LeBEGIN{}
bloc est exécuté avant la première ligne et leEND{}
bloc après la dernière ligne. Ainsi, la commande ci-dessus signifieprint "first" at the beginning, then print every line in the file and print "last" at the end
.Perl
C'est essentiellement la même chose que le gawk ci-dessus qui vient d'être écrit en Perl.
la source
sed -i
ce qui crée des fichiers temporaires.Je préfère le plus simple:
Cela transforme le fichier:
au fichier:
la source
Vous pouvez utiliser Vim en mode Ex:
1
sélectionner la première lignei
insérer du texte et une nouvelle ligne$
sélectionner la dernière lignea
ajouter du texte et une nouvelle lignex
sauver et fermerla source
Il n'y a aucun moyen d'insérer des données au début d'un fichier¹, tout ce que vous pouvez faire est de créer un nouveau fichier, d'écrire les données supplémentaires et d'ajouter les anciennes données. Vous devrez donc réécrire tout le fichier au moins une fois pour insérer la première ligne. Vous pouvez cependant ajouter la dernière ligne sans réécrire le fichier.
Alternativement, vous pouvez combiner les deux commandes en une seule exécution de sed.
sed -i
crée un nouveau fichier de sortie, puis le déplace sur l'ancien fichier. Cela signifie que pendant que sed fonctionne, il existe une deuxième copie du fichier utilisant de l'espace. Vous pouvez éviter cela en écrasant le fichier en place , mais avec des restrictions majeures: la ligne que vous ajoutez doit être plus petite que le tampon de sed, et si votre système plante, vous vous retrouverez avec un fichier endommagé et du contenu perdu dans le milieu, donc je le déconseille fortement.¹ Linux a un moyen d'insérer des données dans un fichier, mais il ne peut insérer qu'un nombre entier de blocs de système de fichiers, il ne peut pas insérer de chaînes de longueurs arbitraires. Il est utile pour certaines applications, telles que les bases de données et les machines virtuelles, mais il est inutile pour les fichiers texte.
la source
fallocate()
avecFALLOC_FL_INSERT_RANGE
disponible sur XFS et ext4 dans les noyaux modernes (4.xx) man7.org/linux/man-pages/man2/fallocate.2.htmlla source
Les noyaux Linux modernes (supérieurs à 4.1 ou 4.2) prennent en charge l'insertion de données au début d'un fichier via l'
fallocate()
appel système avecFALLOC_FL_INSERT_RANGE
les systèmes de fichiers ext4 et xfs. Il s'agit essentiellement d'une opération de décalage logique: les données sont logiquement déplacées à un décalage plus élevé.Il existe une contrainte concernant la granularité de la plage que vous souhaitez insérer au début du fichier. Mais pour les fichiers texte, vous pouvez probablement allouer un peu plus que nécessaire (jusqu'à la limite de granularité) et remplir avec des espaces ou des retours chariot, mais cela dépend de votre application
Je ne connais aucun utilitaire Linux facilement disponible qui manipule les extensions de fichiers mais ce n'est pas difficile à écrire: obtenez un descripteur de fichier et appelez
fallocate()
avec les arguments appropriés. Pour plus de détails, reportez-vous à la page de manuel de l'fallocate
appel système: http://man7.org/linux/man-pages/man2/fallocate.2.htmlla source
fallocate
utilitaire. Le problème est qu'une granularité de blocs entiers rend cela inutile pour la plupart des fichiers texte. Un autre problème est que l'allocation des plages et les modifications ultérieures ne sont pas atomiques. Donc, cela ne résout pas vraiment le problème ici.fallocate
atomicité est cassée, je suis curieux)