Comment puis-je modifier les n dernières lignes d'un fichier?

10

Existe-t-il une commande qui me permettra d'éditer les n dernières lignes d'un fichier? J'ai plusieurs fichiers, qui ont tous un nombre différent de lignes à l'intérieur. Mais je voudrais modifier les n dernières lignes de chaque fichier. L'objectif est de remplacer les virgules par des points-virgules dans les n dernières lignes. Mais seulement dans les toutes dernières n lignes.

Je ne veux supprimer aucune ligne, je veux juste remplacer chaque virgule par un point-virgule dans les n dernières lignes de chaque fichier.

En utilisant la commande sed, je peux remplacer la toute dernière ligne par cette commande. Comme décrit ici: Comment supprimer du texte sur la dernière ligne d'un fichier?

Mais cela ne me permet que de modifier la toute dernière ligne, et non le n dernier nombre de lignes.

sku2003
la source
1
En utilisant simplement sed '24,$s/,/:/g' filename24est la ligne de départ »
Valentin Bajrami

Réponses:

13

Pour remplacer les virgules par des points-virgules sur les n dernières lignes par ed:

n=3
ed -s input <<< '$-'$((n-1))$',$s/,/;/g\nwq'

Séparer cela:

  • ed -s = exécuté en mode silencieux (ne signalez pas les octets écrits à la fin)
  • '$-'= à partir de la fin du fichier ( $) moins ...
  • $((n-1)) = n-1 lignes ...
  • ( $' ... '= cite le reste de la commande pour le protéger du shell)
  • ,$s/,/;/g= ... jusqu'à la fin du fichier ( ,$), recherchez et remplacez toutes les virgules par des points-virgules.
  • \nwq = terminer la commande précédente, puis enregistrer et quitter

Pour remplacer les virgules par des points-virgules sur les n dernières lignes par sed:

n=3
sed -i "$(( $(wc -l < input) - n + 1)),\$s/,/;/g" input

Briser cela:

  • -i = éditer le fichier "sur place"
  • $(( ... )) = faire un peu de calcul:
  • $( wc -l < input) = récupère le nombre de lignes dans le fichier
  • -n + 1 = reculer de n-1 lignes
  • ,\$ = de n-1 lignes jusqu'à la fin du fichier:
  • s/,/;/g = remplacer les virgules par des points-virgules.
Jeff Schaller
la source
Peut remplacer wc -l < inputpar wc -l input. Devrait être plus rapide de quelques nanosecondes :)
gardenhead
1
sauf qu'il wc -l inputaffiche également le nom du fichier; nous ne voulons que le nombre de lignes
Jeff Schaller
Le premier conseil avec ed est fin et simple.
sku2003
En fait, j'ai fini par obtenir de l'aide d'un côté complètement différent. Cela a abouti à ce morceau de code étrange, qui fait l'affaire mais qui est long et étrange. Je suppose que ce sont des choses étranges avec lesquelles vous pouvez vous retrouver quand trouver une solution. Quoi qu'il en soit, le vôtre est plus joli, plus court et moins compliqué que le mien: Le code ici a également fonctionné:
sku2003
cat input.file | sed 's /, /, \ n / g' | sed -n '1! G; h; $ p' | awk -vn = 2 'NR <= n {gsub (",", ";", $ 0)} {print}' | sed -n '1! G; h; $ p' | sed '/ ^ \ s * $ / d'> output.file
sku2003
6

Solution utilisant tac et sed pour remplacer chaque virgule par un point-virgule dans les 50 dernières lignes de file.txt:

tac file.txt | sed '1,50s/,/;/g' | tac
Gohu
la source
5

Avec GNU headet un shell de type Bourne:

n=20
{ head -n -"$n"; tr , ';'; } < file 1<> file

Nous remplaçons le fichier sur lui-même. C'est OK ici pour une translittération d'octet à octet mais pas nécessairement si la modification implique de changer la taille du fichier (dans ce cas, vous voudriez le remplacer 1<> filepar > other-file && mv other-file fileexemple).

Stéphane Chazelas
la source
1
Voici des documents pour1<> lesquels je n'étais pas familier. De plus, spongede moreutils est un bon outil pour les pipelines où vous souhaitez remplacer votre entrée.
Miles
1

Supposons que nous voulons remplacer les dernières 7lignes de la séquence suivante par un script shell et une implémentation GNU de sed:

$ seq 20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Étape 1 : permet d'obtenir le dernier numéro de séquence de la ligne comme suit. Jetez un œil à ceci et à cela :

$ lastLine=`seq 20|sed -n '$='`

$ echo $lastLine 
20

Étape 2 : permet de définir le nombre de lignes (en fin de séquence) que nous souhaitons éditer:

$ numberOfLines=7

$ echo $numberOfLines 
7

Étape 3 : permet de calculer la ligne de départ en fonction des variables précédentes, comme suit. Jetez un œil à ceci :

$ startLine=`expr $lastLine - $numberOfLines + 1`

$ echo $startLine 
14

Étape 4 : Maintenant, nous pouvons remplacer les 7 dernières lignes de séquence par quelque chose d'autre, comme le suivant. Jetez un œil à ceci :

$ seq 20|sed -e "$startLine,+$numberOfLines{s/[12]/WoW/}"
1
2
3
4
5
6
7
8
9
10
11
12
13
WoW4
WoW5
WoW6
WoW7
WoW8
WoW9
WoW0

L'étape 4 utilise la section 4.4 de la page de manuel sed qui dit:

'ADDR1,+N'
     Matches ADDR1 and the N lines following ADDR1.

L'étape 4 utilise également des guillemets doubles comme mentionné ici .


Eh bien, les 4 étapes ne sont pas nécessaires si nous utilisons la réponse de Gohu comme ceci:

$ seq 20 |tac|sed -e '1,7{s/[12]/WoW/}'|tac
1
2
3
4
5
6
7
8
9
10
11
12
13
WoW4
WoW5
WoW6
WoW7
WoW8
WoW9
WoW0
user3405291
la source
0

Utilisation tailet pipe à sed:

tail -n 20 file | sed 's/,/;/g'

Cela fonctionne sur le fichier des 20 dernières lignes. Si vous voulez avoir directement des canges pour l'utilisation du fichier:

tail -n 20 file | sed -i 's/,/;/g'

John Goofy
la source