Besoin de déplacer la dernière ligne du fichier vers la deuxième ligne du même fichier

8

J'ai un fichier «test» sous Linux avec les données ci-dessous.

aaaaaa
bbbbbb
cccccc
dddddd
eeeeee

J'ai besoin de couper la dernière ligne de ce fichier et de le mettre en deuxième position. Il doit ressembler à ci-dessous.

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
Vivek William
la source

Réponses:

9

Ce problème pourrait en fait être plus facile à résoudre ed, car il s'agit essentiellement d'un éditeur de texte scriptable, plutôt que d'un processeur de flux. En utilisant ed, vous n'avez pas à enregistrer toutes les lignes du fichier dans un tableau, par exemple, car il le fait déjà pour vous.

# Create test file
~> printf "%s\n" aaaaaa bbbbbb cccccc dddddd eeeeee >test.txt
~> cat test.txt
aaaaaa
bbbbbb
cccccc
dddddd
eeeeee

# Use ed to open the file, move the last line after the first, save, and quit
~> printf "%s\n" '$m1' wq | ed test.txt
35
35
~> cat test.txt
aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
godlygeek
la source
5

Méthode de mise en mémoire tampon:

sed '$x;1!H;1p;$!d;x;s/\n//
' <<\IN
aaaaaa
bbbbbb
cccccc
dddddd
eeeeee
IN

... qui Hvieillira chaque ligne qui n'est !pas la première, et la première qu'elle pimprime. Sur la $dernière ligne, il xmodifie les espaces d'attente et de motif avant de faire l' Hancien - qui ajoute les lignes enregistrées à la dernière ligne - puis dsupprime de la sortie toutes les lignes qui !ne sont pas les $dernières.

Sur la $dernière ligne, il xmodifie à nouveau les espaces, s///remplace le premier \ncaractère de ligne électronique - qui prend en charge le supplément ajouté sur la ligne 2 - puis imprime automatiquement le lot.

PRODUCTION:

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

sans utiliser le tampon Hold:

cat <<\IN >infile
aaaaaa
bbbbbb
cccccc
dddddd
eeeeee
IN

... juste pour enregistrer votre exemple dans un fichier réel ...

sed '1p;$!d;r infile' <infile | sed '3d;$d'

Redirigeant <infileaux premiers sed« s stdin, qui ne prints la première ligne avant deleting de sortie toutes les lignes qui ne sont !pas la $dernière. La dernière ligne est autoprinted, mais il est aussi la seule ligne sur laquelle la dernière commande est exécutée - qui est à read sur l'ensemble de infile nouveau à stdout. Tout cela passe par le |tuyau vers le second sedqui n'a alors qu'à dsupprimer de sa sortie ses troisième et dernière lignes d'entrée pour terminer la réorganisation.

PRODUCTION:

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
mikeserv
la source
cool, +1. Je ne me souviens pas que vous ayez jamais publié de awksolutions, êtes-vous un grand sedfan ou peut-être avez-vous écrit sed? ;-)
iruvar
@ 1_CR - je ne sais pas comment utiliser awk- je n'ai jamais essayé. peut-être un jour ...
mikeserv
2

Une approche naïve avec awk:

~$ awk '{a[NR]=$0}END{print a[1];print a[NR];for(i=2;i<NR;i++){print a[i]}}' f
aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

Vous stockez chaque ligne dans le atableau, puis imprimez le tableau dans l'ordre souhaité (1ère ligne, dernière ( NR) et de 2 à l'avant-dernière.

En utilisant une combinaison tête / queue et sed:

~$ head -1 f;tail -1 f;sed '1d;$d' f
aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

Imprimez la première ligne, la dernière et avec sed supprimez la 1ère et la dernière.


Avec sed uniquement, je n'ai pu trouver que cette commande. Je suis sûr qu'il existe de meilleures façons:

~$ sed '${p;x;s/^\n//;p};2,${H;d}' f
aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

S'il s'agit de la première ligne, imprimez-la (par défaut).
À partir de la deuxième ligne, placez-le dans le tampon de maintien ( H) et supprimez-le de l'espace de motif ( d). Et si c'est la dernière ligne, imprimez-la ( p), puis récupérez le tampon de maintien ( x), supprimez la ligne vide ( s/^\n//) et imprimez-la ( p).

fredtantini
la source
Mon premier réflexe serait d'utiliser la méthode tête / queue. Une alternative à la sedpièce serait quelque chose comme head -n -1 f | tail -n +2.
Sparhawk
@Sparhawk la -1syntaxe headn'est pas portable.
mikeserv
1

Avec perl:

perl -e 'my @lines = <>; print for @lines[0, $#lines, 1..$#lines-1]' file

Avec awk:

$ awk '
    {lines[NR]=$0}
    END{
        print lines[1], lines[NR];
        for (i=2; i<NR; i++) {print lines[i]}
    }
' OFS=$'\n' file

PRODUCTION

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
Gilles Quenot
la source