J'ai besoin de supprimer à plusieurs reprises la première ligne d'un énorme fichier texte à l'aide d'un script bash.
En ce moment j'utilise sed -i -e "1d" $FILE
- mais cela prend environ une minute pour faire la suppression.
Existe-t-il un moyen plus efficace d'y parvenir?
Réponses:
Essayez la queue :
-n x
: Imprimez simplement les dernièresx
lignes.tail -n 5
vous donnerait les 5 dernières lignes de l'entrée. Le+
signe inverse en quelque sorte l'argument et faittail
imprimer tout sauf les premièresx-1
lignes.tail -n +1
imprimerait tout le fichier,tail -n +2
tout sauf la première ligne, etc.GNU
tail
est beaucoup plus rapide quesed
.tail
est également disponible sur BSD et l'-n +2
indicateur est cohérent entre les deux outils. Consultez les pages de manuel FreeBSD ou OS X pour en savoir plus.sed
Cependant, la version BSD peut être beaucoup plus lente . Je me demande comment ils ont géré cela;tail
devrait simplement lire un fichier ligne par ligne tout ensed
effectuant des opérations assez complexes impliquant l'interprétation d'un script, l'application d'expressions régulières, etc.Remarque: vous pourriez être tenté d'utiliser
mais cela vous donnera un fichier vide . La raison en est que la redirection (
>
) se produit avant d'tail
être invoquée par le shell:$FILE
tail
tail
processus vers$FILE
tail
lit à partir de maintenant vide$FILE
Si vous souhaitez supprimer la première ligne à l'intérieur du fichier, vous devez utiliser:
Le
&&
fera en sorte que le fichier ne soit pas écrasé en cas de problème.la source
-r
option. Peut-être qu'il y a un paramètre de tampon quelque part dans le système? Ou-n
est un numéro signé 32 bits?tail
fonctionnera pour n'importe quelle taille de fichier.-n N means output the last N lines, instead of the last 10; or use +N to output lines starting with the Nth
Vous pouvez utiliser -i pour mettre à jour le fichier sans utiliser l'opérateur '>'. La commande suivante supprimera la première ligne du fichier et l'enregistrera dans le fichier.
la source
unterminated transform source string
sed -i '1,2d' filename
tail -n +2
. Je ne sais pas pourquoi ce n'est pas la meilleure réponse.Pour ceux qui sont sur SunOS qui n'est pas GNU, le code suivant vous aidera:
la source
Non, c'est aussi efficace que possible. Vous pouvez écrire un programme C qui pourrait faire le travail un peu plus rapidement (moins de temps de démarrage et d'arguments de traitement) mais il tendra probablement vers la même vitesse que sed lorsque les fichiers deviennent volumineux (et je suppose qu'ils sont volumineux si cela prend une minute ).
Mais votre question souffre du même problème que tant d'autres en ce qu'elle présuppose la solution. Si vous deviez nous dire en détail ce que vous essayez de faire plutôt que comment , nous pourrions peut-être vous proposer une meilleure option.
Par exemple, s'il s'agit d'un fichier A que certains autres programmes B traitent, une solution serait de ne pas supprimer la première ligne, mais de modifier le programme B pour le traiter différemment.
Supposons que tous vos programmes s'ajoutent à ce fichier A et que le programme B lit et traite actuellement la première ligne avant de le supprimer.
Vous pouvez réorganiser le programme B pour qu'il n'essaye pas de supprimer la première ligne mais conserve un décalage persistant (probablement basé sur un fichier) dans le fichier A afin que, la prochaine fois qu'il s'exécute, il puisse rechercher ce décalage, traiter la ligne là-bas et mettre à jour le décalage.
Ensuite, à une heure 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 d'ouvrir et de réécrire. Cette discussion suppose que vous avez le contrôle sur le 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.
la source
awk FNR-1 *.csv
est probablement plus rapide.Vous pouvez éditer les fichiers en place: Utilisez simplement le
-i
drapeau de perl , comme ceci:Cela fait disparaître la première ligne, comme vous le demandez. Perl devra lire et copier l'intégralité du fichier, mais il organise l'enregistrement de la sortie sous le nom du fichier d'origine.
la source
Vous pouvez facilement le faire avec:
sur la ligne de commande; ou pour supprimer définitivement la première ligne d'un fichier, utilisez le mode in-situ de sed avec le
-i
flag:la source
Comme l'a dit Pax, vous n'allez probablement pas aller plus vite que cela. La raison en est qu'il n'y a presque aucun système de fichiers qui prend en charge la troncature depuis le début du fichier, donc cela va être une
n
opération O ( ) oùn
est la taille du fichier. Ce que vous pouvez faire beaucoup plus rapidement 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 fonctionner pour vous selon exactement ce que vous essayez de faire (qu'est-ce que c'est d'ailleurs?).la source
L'
sponge
utilitaire évite d'avoir à jongler avec un fichier temporaire:la source
sponge
est en effet beaucoup plus propre et plus robuste que la solution acceptée (tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
)sponge
mémoire tampon tout le fichier? Cela ne fonctionnera pas si c'est des centaines de Go.sponge
il l'absorbera, car il utilise un fichier / tmp comme étape intermédiaire, qui est ensuite utilisé pour remplacer l'original par la suite.Si vous souhaitez modifier le fichier en place, vous pouvez toujours utiliser l'original
ed
au lieu de son successeur s treamingsed
:La
ed
commande était l'éditeur de texte UNIX d'origine, avant même d'avoir des terminaux plein écran, et encore moins des postes de travail graphiques. Leex
rédacteur en chef, mieux connu sous le nom que vous utilisez lors de la saisie à l'invite du côlon dansvi
, est une ex la version de tendanceed
, tant du même travail de commandes. Bien qu'iled
soit destiné à être utilisé de manière interactive, il peut également être utilisé en mode batch en lui envoyant une chaîne de commandes, ce que fait cette solution.La séquence
<<<$'1d\nwq\n'
profite de l'appui de bash pour ici cordes (<<<
) et des citations POSIX ($'
...'
) à l' entrée d'alimentation de laed
commande se compose de deux lignes:1d
qui d eletes aligner 1 , et ensuitewq
, ce qui w rites au dos du dossier vers disque, puis q uits la session d'édition.la source
devrait montrer les lignes sauf la première ligne:
la source
Pourrait utiliser vim pour ce faire:
Cela devrait être plus rapide, car vim ne lira pas le fichier entier lors du processus.
la source
+wq!
si votre shell est bash. Probablement pas car le!
n'est pas au début d'un mot, mais prendre l'habitude de citer des choses est probablement bon tout autour. (Et si vous optez pour la super-efficacité en ne citant pas inutilement, vous n'avez pas besoin des guillemets1d
non plus.)Que diriez-vous d'utiliser csplit?
la source
csplit file /^.*$/1
. Ou plus simplement:csplit file //1
. Ou encore plus simplement:csplit file 2
.Comme il semble que je ne puisse pas accélérer la suppression, je pense qu'une bonne approche pourrait être de traiter le fichier par lots comme celui-ci:
L'inconvénient est que si le programme est tué au milieu (ou s'il y a un mauvais sql - provoquant la mort ou le blocage de la partie "processus"), il y aura des lignes qui seront soit ignorées, soit traitées deux fois .
(le fichier1 contient des lignes de code sql)
la source
Si ce que vous cherchez à faire est de récupérer après l'échec, vous pouvez simplement créer un fichier contenant ce que vous avez fait jusqu'à présent.
la source
Cette doublure fera:
Cela fonctionne, car il
tail
est exécuté avantecho
et ensuite le fichier est déverrouillé, donc pas besoin de fichier temporaire.la source
Est-ce que l'utilisation de la queue sur les lignes N-1 et de la diriger vers un fichier, puis de supprimer l'ancien fichier et de renommer le nouveau fichier en l'ancien nom ferait le travail?
Si je faisais cela par programme, je lirais le fichier et me souviendrais de l'offset du fichier, après avoir lu chaque ligne, afin que je puisse revenir à cette position pour lire le fichier avec une ligne en moins.
la source