Comment imprimer la première colonne de la ligne suivante dans la ligne actuelle?

8

J'ai un fichier comme celui-ci:

abc 123    
abc 789  
bcd 456  
acb 135

Je voudrais imprimer la première colonne de la ligne suivante dans la ligne actuelle.

Sortie désirée:

abc  123 abc  
abc 789 bcd  
bcd 456 acb  
acb 135 

Je préfère utiliser awk.

user2905046
la source

Réponses:

16

Mémorisez la ligne précédente:

awk 'NR > 1 { print prev, $1 } { prev = $0 } END { print prev }'

Cela traite l'entrée comme suit:

  • si la ligne actuelle est la seconde ou plus, imprimez la ligne précédente (stockée dans prev, voir l'étape suivante) et le premier champ de la ligne actuelle, séparés par le séparateur de champ de sortie (le caractère espace par défaut);
  • dans tous les cas, stockez la ligne courante dans la prevvariable;
  • à la fin du fichier, imprimez la ligne précédente.
Stephen Kitt
la source
11

awkApproche alternative :

$ awk 'NR == 1{printf "%s", $0;next}{printf " %s\n%s", $1,$0}' input.txt                                    
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135

La façon dont cela fonctionne est simple: la première ligne est un cas spécial - nous l'imprimons sans nouvelle ligne, et demandons à awk d'aller à la ligne suivante sans exécuter d'autres blocs de code. Après cela, NR == 1{printf "%s", $0;next}est ignoré, mais d'autres parties font le travail.

N'oubliez pas que jusqu'à présent, nous avons imprimé une chaîne formatée sans nouveau caractère de ligne. Ainsi, ce qui se fait printf " %s\n%s",$1,$0maintenant, c'est que le premier mot est imprimé (et parce qu'il n'y avait pas de nouvelle ligne, il reste sur la même ligne de sortie), la nouvelle ligne insérée, puis la ligne entière elle-même (mais ne se termine pas par le caractère de nouvelle ligne) . Ainsi, le premier premier mot inséré restera sur la même ligne. Le processus se poursuit indéfiniment jusqu'à la fin du fichier.

L'amélioration possible consiste à inclure un END{print ""}bloc pour insérer la nouvelle ligne finale. Dans certains cas, lorsque le fichier résultant doit être traité par d'autres scripts, il peut être souhaitable.


Bien que l'utilisateur ait spécifiquement demandé AWK, la même approche avec l'impression de chaînes formatées peut être adoptée avec d'autres langues, par exemple Python. Alternative Python fournie pour ceux curieux de savoir comment cela peut être implémenté dans d'autres langues:

#!/usr/bin/env python
from __future__ import print_function
import sys

old = None
for index,line in enumerate(sys.stdin):
    if index == 0:
        print(line.strip(),end=" ")
        continue
    words = line.strip().split()
    print(words[0] + "\n" + line.strip(),end=" ")

Et une utilisation comme ça:

$ ./append_first.py < input.txt                            
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135

La même idée sur la nouvelle ligne finale s'applique ici.

Sergiy Kolodyazhnyy
la source
9

Voici une sedfaçon laide juste pour le plaisir

sed '2,$ s/[^ ]\+/& &/; 2,$ s/ /\n/' file | paste -d ' ' - -
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135 

Explication

  • 2,$ de la deuxième ligne à la dernière
  • s/[^ ]\+/& &/ doubler le premier jeu de caractères non blancs
  • ; sépare les commandes, comme dans le shell
  • s/ /\n/ remplacer le premier espace par une nouvelle ligne
  • paste -d ' ' - - coller ce désordre ensemble (ajouter la deuxième ligne au troisième, la quatrième ligne au troisième, etc.)
Zanna
la source
1
Alternativement, vous pouvez utiliser sedseul sans paste:sed -r 'N;s/\n(\w+)/\1&/;P;D' somefile.txt
Digital Trauma
1
Si vous écrivez des sedprogrammes pour le plaisir, alors vous devriez peut-être essayer le code-golf ;-)
Digital Trauma
1
@DigitalTrauma, elle est sur le code-golf depuis 2 mois déjà;)
Sergiy Kolodyazhnyy
1

À mon avis, l'approche la plus simple et la plus lisible est:

  1. extraire la première colonne ( cut)
  2. supprimez la première ligne de votre colonne extraite ( tail)
  3. collez cette colonne dans votre fichier source ( paste)

Exemple: votre exemple de fichier inpult:

abc 123    
abc 789  
bcd 456  
acb 135

Exécutez ensuite la commande suivante dans un terminal

cut -d' ' -f1 in.txt | tail -n +2 | paste -d' ' file -

Production:

abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135

La structure derrière cette solution diffère des réponses données. Pas besoin de conditions, de boucles ou d'expression régulière.

Hölderlin
la source