Si ce «grand» signifie environ 10 millions de lignes ou plus, mieux vaut l'utiliser tail. N'est pas capable de montage sur place, mais ses performances rendent ce manque pardonnable:
tail -n +2 large_file > large_file.new
Modifiez pour afficher certaines différences de temps:
( awkcode de Jaypal ajouté pour avoir des temps d'exécution sur la même machine (CPU 2,2 GHz).)
bash-4.2$ seq 1000000 > bigfile.txt # further file creations skipped
bash-4.2$ time sed -i 1d bigfile.txt
time 0m4.318s
bash-4.2$ time ed -s <<< $'1d\nwq' bigfile.txt
time 0m0.533s
bash-4.2$ time perl -pi -e 'undef$_ if$.==1' bigfile.txt
time 0m0.626s
bash-4.2$ time { tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt; }
time 0m0.034s
bash-4.2$ time { awk 'NR>1 {print}' bigfile.txt > newfile.txt && mv -f newfile.txt bigfile.txt; }
time 0m0.328s
Dans ce cas tail, je préfère compter le temps pour faire à la fois supprimer la première ligne et remplacer bigfile.txtpar bigfile.new.
rozcietrzewiacz
@rozcietrzewiacz, votre point est correct. Merci. Mis à jour.
manatwork
C'est vraiment cool! J'ai fait la même chose avec awket j'ai obtenu le résultat suivant -[jaypal:~/Temp] seq 1000000 > bigfile.txt [jaypal:~/Temp] time awk 'NR>1 {print}' bigfile.txt >newfile.txt real 0m0.649s user 0m0.601s sys 0m0.033s
jaypal singh
1
@Jaypal, j'ai ajouté votre code à la liste des alternatives. Sur ma machine, c'était encore plus rapide. Étrange, je m'attendais à awkune performance plus proche de celle sedde. (Remarque pour moi-même: ne vous attendez jamais - testez à la place.)
Manatwork
C'était la meilleure solution dans mon cas: tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt;j'utilise un seul fichier avec un verrou pour garder une trace d'une seule liste de tâches utilisée par plusieurs processus. J'ai commencé avec ce que l'affiche initiale utilisée: sed -i 1d large_file . Cela provoquait le verrouillage du fichier pendant 1 à 2 secondes. Le tail/mvcombo se termine presque instantanément. Merci!
Chris Adams
6
Il n'y a aucun moyen de supprimer efficacement des éléments au début d'un fichier. La suppression des données depuis le début nécessite la réécriture de tout le fichier.
La troncature à partir de la fin d'un fichier peut cependant être très rapide (le système d'exploitation n'a qu'à ajuster les informations sur la taille du fichier, éventuellement en supprimant les blocs non utilisés). Ce n'est généralement pas possible lorsque vous essayez de supprimer de la tête d'un fichier.
Cela pourrait théoriquement être "rapide" si vous supprimiez exactement un bloc / une étendue, mais il n'y a pas d'appels système pour cela, vous devrez donc vous fier à la sémantique spécifique au système de fichiers (si cela existe). (Ou avoir une certaine forme de décalage à l'intérieur du premier bloc / étendue pour marquer le début réel du fichier, je suppose. Je n'en ai jamais entendu parler non plus.)
Si le fichier est très volumineux, la surcharge d'E / S est susceptible d'être (peut-être beaucoup) supérieure à la surcharge du processeur requise pour traiter la fin des lignes.
Mat
Vous avez raison. Cependant, il peut y avoir une différence dans la façon dont les outils accèdent au contenu du fichier. Le mieux n'est pas de traiter ligne par ligne quand ce n'est pas nécessaire ou du moins de ne pas lire ligne par ligne quand ce n'est pas nécessaire.
manatwork
2
Je suis surpris que la différence soit si grande dans vos résultats et puisse la reproduire avec cette taille de fichier ici. Les avantages semblent diminuer à mesure que la taille du fichier augmente (essayé avec seq 10M, 15s pour sed, 5s pour ed). Bons conseils quand même (+1).
Mat
À partir de la version 3.15, Linux dispose désormais d'une API pour réduire des parties d'un fichier sur des systèmes de fichiers basés sur une certaine étendue, mais au moins pour ext4 qui ne peut être fait que sur des blocs complets (généralement 4k).
Stéphane Chazelas
Même si l'édition nécessite la réécriture de l'intégralité du fichier, il est parfois très pratique d'avoir des outils en ligne de commande pour éditer efficacement. Dans mon cas, cela a aidé lorsque j'ai dû supprimer la première ligne d'un fichier qui était plus grande que la RAM totale de mon système.
Jason
3
La méthode la plus efficace, ne le faites pas! Si vous le faites, dans tous les cas, vous avez besoin du double du «grand» espace sur le disque et vous gaspillez les E / S.
Si vous êtes bloqué avec un gros fichier que vous souhaitez lire sans la 1ère ligne, attendez d'avoir besoin de le lire pour supprimer la 1ère ligne. Si vous devez envoyer le fichier de stdin à un programme, utilisez tail pour le faire:
tail -n +2 | your_program
Lorsque vous devez lire le fichier, vous pouvez en profiter pour supprimer la 1ère ligne, mais uniquement si vous disposez de l'espace nécessaire sur le disque:
tail -n +2 | tee large_file2 | your_program
Si vous ne pouvez pas lire depuis stdin, utilisez un fifo:
encore mieux si vous utilisez bash, profitez de la substitution de processus:
your_program -i <(tail -n +2 large_file)
Si vous avez besoin de rechercher dans le fichier, je ne vois pas de meilleure solution que de ne pas rester coincé avec le fichier en premier lieu. Si ce fichier a été généré par stdout:
large_file_generator | tail -n +2 > large_file
Sinon, il y a toujours la solution de substitution fifo ou process:
Un système de fichiers personnalisé (implémenté à l'aide de FUSE ou d'un mécanisme similaire) pourrait exposer un répertoire dont le contenu est exactement le même qu'un répertoire déjà existant ailleurs, mais avec des fichiers tronqués comme vous le souhaitez. Le système de fichiers traduirait tous les décalages de fichiers. Ensuite, vous n'auriez pas à réécrire un fichier avec beaucoup de temps.
Mais étant donné que cette idée est très simple, à moins que vous n'ayez des dizaines de téraoctets de tels fichiers, la mise en œuvre d'un tel système de fichiers serait trop coûteuse / longue pour être pratique.
tail
, je préfère compter le temps pour faire à la fois supprimer la première ligne et remplacerbigfile.txt
parbigfile.new
.awk
et j'ai obtenu le résultat suivant -[jaypal:~/Temp] seq 1000000 > bigfile.txt [jaypal:~/Temp] time awk 'NR>1 {print}' bigfile.txt >newfile.txt real 0m0.649s user 0m0.601s sys 0m0.033s
awk
une performance plus proche de cellesed
de. (Remarque pour moi-même: ne vous attendez jamais - testez à la place.)tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt;
j'utilise un seul fichier avec un verrou pour garder une trace d'une seule liste de tâches utilisée par plusieurs processus. J'ai commencé avec ce que l'affiche initiale utilisée:sed -i 1d large_file
. Cela provoquait le verrouillage du fichier pendant 1 à 2 secondes. Letail/mv
combo se termine presque instantanément. Merci!Il n'y a aucun moyen de supprimer efficacement des éléments au début d'un fichier. La suppression des données depuis le début nécessite la réécriture de tout le fichier.
La troncature à partir de la fin d'un fichier peut cependant être très rapide (le système d'exploitation n'a qu'à ajuster les informations sur la taille du fichier, éventuellement en supprimant les blocs non utilisés). Ce n'est généralement pas possible lorsque vous essayez de supprimer de la tête d'un fichier.
Cela pourrait théoriquement être "rapide" si vous supprimiez exactement un bloc / une étendue, mais il n'y a pas d'appels système pour cela, vous devrez donc vous fier à la sémantique spécifique au système de fichiers (si cela existe). (Ou avoir une certaine forme de décalage à l'intérieur du premier bloc / étendue pour marquer le début réel du fichier, je suppose. Je n'en ai jamais entendu parler non plus.)
la source
La méthode la plus efficace, ne le faites pas! Si vous le faites, dans tous les cas, vous avez besoin du double du «grand» espace sur le disque et vous gaspillez les E / S.
Si vous êtes bloqué avec un gros fichier que vous souhaitez lire sans la 1ère ligne, attendez d'avoir besoin de le lire pour supprimer la 1ère ligne. Si vous devez envoyer le fichier de stdin à un programme, utilisez tail pour le faire:
Lorsque vous devez lire le fichier, vous pouvez en profiter pour supprimer la 1ère ligne, mais uniquement si vous disposez de l'espace nécessaire sur le disque:
Si vous ne pouvez pas lire depuis stdin, utilisez un fifo:
encore mieux si vous utilisez bash, profitez de la substitution de processus:
Si vous avez besoin de rechercher dans le fichier, je ne vois pas de meilleure solution que de ne pas rester coincé avec le fichier en premier lieu. Si ce fichier a été généré par stdout:
Sinon, il y a toujours la solution de substitution fifo ou process:
la source
Vous pouvez utiliser Vim en mode Ex:
1
sélectionner la première ligned
supprimerx
sauver et fermerla source
C'est juste de la théorie, mais ...
Un système de fichiers personnalisé (implémenté à l'aide de FUSE ou d'un mécanisme similaire) pourrait exposer un répertoire dont le contenu est exactement le même qu'un répertoire déjà existant ailleurs, mais avec des fichiers tronqués comme vous le souhaitez. Le système de fichiers traduirait tous les décalages de fichiers. Ensuite, vous n'auriez pas à réécrire un fichier avec beaucoup de temps.
Mais étant donné que cette idée est très simple, à moins que vous n'ayez des dizaines de téraoctets de tels fichiers, la mise en œuvre d'un tel système de fichiers serait trop coûteuse / longue pour être pratique.
la source