Comment imprimer tout sauf la Nième à la dernière ligne dans sed?

9
  • Je voudrais faire le complément / "l'opposé" de

    sed 13q;d <file.txt
    

    Plus généralement, est-il possible de faire ce genre de complément / inverse / opposé en sed? Ou seulement pour les regexes?

  • Comment imprimer tout sauf l'avant-dernière ligne?. Est-ce que cela nécessite deux tacet compte à rebours sed? Ou existe-t-il un moyen de se sedfaire compter de dos?

isomorphismes
la source

Réponses:

12

Partie 1

dSupprimez simplement la 13e ligne:

sed '13d' <file.txt

Et une façon générale de faire le complément de ce qui précède est:

sed '13!d' <file.txt

Partie 2

Parce que cela peut être fait:

sed -n ':a;${P;q};N;4,$D;ba' <file.txt

Notez que 4c'est un de plus que le nombre dont vous avez besoin. Donc, si vous vouliez la dernière 10e ligne, ce serait 11.

Test avec seq:

$ seq 100 | sed -n ':a;${P;q};N;4,$D;ba'
98
$ 

Tentative d'explication

:a        # define label a
${        # match the last line
    P     # print the first line of the pattern space
    q     # quit
}
N         # match all lines: append the next line to the pattern
4,${      # match the range of lines 4 to the end of the file
    D     # delete the first line of the pattern space
}
ba        # match all lines: jump back to label a 

L'ajout précieux de Glenn Jackman:

C'était "seulement la Nième ligne". Voici "tout MAIS la Nième ligne":

sed -n ':a;${s/^[^\n]*\n//;p;q};N;4,${P;D};ba'

fonctionne avec GNU sed, la \nséquence peut ne pas fonctionner avec d'autres seds.


J'ai essayé cela avec BSD sed (OSX) et j'ai trouvé que cela ne fonctionnait pas tout à fait dans le formulaire ci-dessus. Les problèmes semblent être les suivants:

  1. ; utilisé pour séparer les lignes semble généralement fonctionner, mais ne fonctionne pas après une étiquette
  2. BSD sed semble exiger ;après la dernière commande d'un {}groupe de commandes sur une ligne , alors que GNU sed ne
  3. \npeut généralement être utilisé dans l'expression régulière, mais apparemment pas dans une []expression entre crochets. Donc, pour exclure les nouvelles lignes, nous pouvons utiliser quelque chose comme à la [[:alnum:][:punct:][:graph:][:blank:]]place, bien que cela puisse exclure d'autres caractères (en particulier d'autres caractères de contrôle).

Il s'agit donc d'une tentative de version plus indépendante de la plateforme:

sed -n ':a
${s/^[[:alnum:][:punct:][:graph:][:blank:]]*\n//p;q;};N;4,${P;D;};ba'

Cela semble fonctionner sous OSX et Ubuntu.

Traumatisme numérique
la source
@jimmij Les autres réponses sur des questions connexes dans le réseau SE suggèrent qu'une solution head/ tailest beaucoup plus lente qu'une sedsolution. Merci quand même.
isomorphismes
3
@isomorphismes aucun programme ne peut connaître le nombre de lignes dans un fichier à moins qu'il ne traverse tout le fichier. Il n'y a aucun moyen de contourner cela. La seule façon de compter à partir du bas consiste à inverser le fichier et à compter à partir du haut ou à l'analyser deux fois. Donc, la tête / queue va être à peu près aussi rapide que possible.
terdon
@isomorphismes ... car ils ( head/ tail) sont optimisés pour faire ce qu'ils font.
peterph
@isomorphismes - édité avec toutes les pièces dont vous avez besoin
Digital Trauma
Agréable! J'ai dû changer ma réponse, car je m'attendais à ce que ce soit plus compliqué. :)
peterph