Comment puis-je supprimer la première ligne d’un fichier texte en utilisant le script bash / sed?

Je dois supprimer à plusieurs resockets la première ligne d’un énorme fichier texte en utilisant un script bash.

En ce moment, j’utilise sed -i -e "1d" $FILE – mais la suppression prend environ une minute.

Existe-t-il un moyen plus efficace d’y parvenir?

Essayez la queue GNU :

 tail -n +2 "$FILE" 

-nx : imprimez simplement les dernières lignes x . tail -n 5 vous donnerait les 5 dernières lignes de l’entrée. Le signe + inverse en quelque sorte l’argument et fait que la tail imprime tout sauf les premières lignes x-1 . tail -n +1 imprime le fichier entier, tail -n +2 tout sauf la première ligne, etc.

GNU tail est beaucoup plus rapide que sed . tail est également disponible sur BSD et l’indicateur -n +2 est cohérent sur les deux outils. Consultez les pages de manuel FreeBSD ou OS X pour plus d’informations.

La version BSD peut cependant être beaucoup plus lente que sed . Je me demande comment ils ont réussi ça; tail doit simplement lire un fichier ligne par ligne alors que sed effectue des opérations assez complexes impliquant l’interprétation d’un script, l’application d’expressions régulières, etc.

Note: Vous pourriez être tenté d’utiliser

 # THIS WILL GIVE YOU AN EMPTY FILE! tail -n +2 "$FILE" > "$FILE" 

mais cela vous donnera un fichier vide . La raison en est que la redirection ( > ) se produit avant que tail soit appelé par le shell:

  1. Shell tronque le fichier $FILE
  2. Shell crée un nouveau processus pour la tail
  3. Shell redirige stdout du processus de tail vers $FILE
  4. tail lit depuis le maintenant vide $FILE

Si vous souhaitez supprimer la première ligne du fichier, vous devez utiliser:

 tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE" 

Le && fera en sorte que le fichier ne soit pas écrasé en cas de problème.

Vous pouvez utiliser -i pour mettre à jour le fichier sans utiliser l’opérateur ‘>’. La commande suivante supprime la première ligne du fichier et l’enregistre dans le fichier.

 sed -i '1d' filename 

Pour ceux qui sont sur SunOS non GNU, le code suivant vous aidera:

 sed '1d' test.dat > tmp.dat 

Non, c’est à peu près aussi efficace que vous allez l’obtenir. Vous pourriez écrire un programme C qui pourrait faire le travail un peu plus rapidement (moins de temps de démarrage et de traitement des arguments) mais il aura probablement la même vitesse que sed car les fichiers sont volumineux (et je suppose qu’ils sont volumineux ).

Mais votre question souffre du même problème que tant d’autres en ce sens qu’elle suppose la solution. Si vous deviez nous dire en détail ce que vous essayez de faire plutôt que comment , nous pourrons peut-être suggérer une meilleure option.

Par exemple, s’il s’agit d’un fichier A traité par d’autres programmes B, une solution consisterait à ne pas supprimer la première ligne, mais à modifier le programme B pour le traiter différemment.

Disons que tous vos programmes sont ajoutés à ce fichier A et que le programme B lit et traite la première ligne avant de le supprimer.

Vous pouvez réorganiser le programme B pour qu’il ne tente pas de supprimer la première ligne, mais conserve un décalage persistant (probablement basé sur le fichier) dans le fichier A, de sorte que la prochaine fois qu’il s’exécute, il la ligne là-bas et mettre à jour le décalage.

Puis, à un moment calme (minuit?), Il pourrait effectuer un traitement spécial du fichier A pour supprimer toutes les lignes actuellement traitées et remettre le décalage à 0.

Il sera certainement plus rapide pour un programme d’ouvrir et de rechercher un fichier plutôt que de l’ouvrir et de le réécrire. Cette discussion suppose que vous avez le contrôle du programme B, bien sûr. Je ne sais pas si c’est le cas, mais il peut y avoir d’autres solutions possibles si vous fournissez des informations supplémentaires.

Vous pouvez éditer les fichiers en place: utilisez simplement le drapeau perl’s -i , comme ceci:

 perl -ni -e 'print unless $. == 1' filename.txt 

Cela fait disparaître la première ligne, comme vous le demandez. Perl devra lire et copier l’intégralité du fichier, mais il faudra que la sortie soit enregistrée sous le nom du fichier d’origine.

Comme Pax l’a dit, vous n’allez probablement pas plus vite que ça. La raison en est qu’il n’existe pratiquement aucun système de fichiers prenant en charge la troncature depuis le début du fichier. Il s’agit donc d’une opération O ( n ) où n correspond à la taille du fichier. Ce que vous pouvez faire beaucoup plus rapidement, cependant, est d’écraser la première ligne avec le même nombre d’octets (peut-être avec des espaces ou un commentaire), ce qui pourrait vous convenir en fonction de ce que vous essayez de faire.

devrait montrer les lignes sauf la première ligne:

 cat textfile.txt | tail -n +2 

L’ sponge util évite d’avoir à jongler avec un fichier temporaire:

 tail -n +2 "$FILE" | sponge "$FILE" 

Que diriez-vous d’utiliser csplit?

 man csplit csplit -k file 1 '{1}' 

Pourrait utiliser vim pour faire ceci:

 vim -u NONE +'1d' +'wq!' /tmp/test.txt 

Cela devrait être plus rapide, car vim ne lira pas tout le fichier lors du processus.

Si vous voulez modifier le fichier en place, vous pouvez toujours utiliser l’ ed original au lieu de son successeur

 ed "$FILE" < <<$'1d\nwq\n' 

Comme il semble que je ne puisse pas accélérer la suppression, je pense qu’une bonne approche pourrait consister à traiter le fichier en lots comme ceci:

 While file1 not empty file2 = head -n1000 file1 process file2 sed -i -e "1000d" file1 end 

L’inconvénient est que si le programme est tué au milieu (ou s’il y a du mauvais SQL dans celui-ci – provoquant la mort ou le blocage de la partie “process”), il y aura des lignes soit ignorées, soit traitées deux fois. .

(fichier1 contient des lignes de code SQL)

Si ce que vous cherchez à faire est de récupérer après un échec, vous pouvez simplement créer un fichier qui a ce que vous avez fait jusqu’à présent.

 if [[ -f $tmpf ]] ; then rm -f $tmpf fi cat $srcf | while read line ; do # process line echo "$line" >> $tmpf done 

Est-ce que l’utilisation de tail sur les lignes N-1 et la direction dans un fichier, suivie de la suppression de l’ancien fichier et du changement de nom du nouveau fichier à l’ancien nom font l’affaire?

Si je le faisais par programmation, je lirais le fichier et me souviendrais du décalage du fichier, après avoir lu chaque ligne, afin de pouvoir revenir à cette position pour lire le fichier avec une ligne de moins.