web-dev-qa-db-fra.com

Comment fusionner toutes les deux lignes en une ligne à partir de la ligne de commande?

J'ai un fichier texte au format suivant. La première ligne est la "KEY" et la deuxième ligne est la "valeur".

KEY 4048:1736 string
3
KEY 0:1772 string
1
KEY 4192:1349 string
1
KEY 7329:2407 string
2
KEY 0:1774 string
1

J'ai besoin de la valeur dans la même ligne que de la clé. Donc, la sortie devrait ressembler à ceci ...

KEY 4048:1736 string 3
KEY 0:1772 string 1
KEY 4192:1349 string 1
KEY 7329:2407 string 2
KEY 0:1774 string 1

Ce sera mieux si je pouvais utiliser un délimiteur comme $ ou ,:

KEY 4048:1736 string , 3

Comment fusionner deux lignes en une seule?

129
shantanuo

awk:

awk 'NR%2{printf "%s ",$0;next;}1' yourFile

remarque, il y a une ligne vide à la fin de la sortie.

sed:

sed 'N;s/\n/ /' yourFile
159
Kent

paste est bon pour ce travail:

paste -d " "  - - < filename
212
glenn jackman

Alternative à sed, awk, grep:

xargs -n2 -d'\n'

Ceci est préférable lorsque vous souhaitez joindre N lignes et que vous n’avez besoin que d’une sortie délimitée par des espaces.

Ma réponse initiale était xargs -n2 qui sépare les mots plutôt que les lignes. -d peut être utilisé pour scinder l'entrée en un seul caractère.

29
nnog

Il y a plus de façons de tuer un chien que de pendre. [1]

awk '{key=$0; getline; print key ", " $0;}'

Mettez le délimiteur que vous aimez dans les guillemets.


Références:

  1. A l'origine "Beaucoup de façons de peauner le chat", est revenu à une expression plus ancienne, potentiellement originaire, qui n'a également rien à voir avec les animaux domestiques.
25
ghoti

Voici un autre moyen avec awk:

awk 'ORS=NR%2?FS:RS' file
$ cat file
KEY 4048:1736 string
3
KEY 0:1772 string
1
KEY 4192:1349 string
1
KEY 7329:2407 string
2
KEY 0:1774 string
1
$ awk 'ORS=NR%2?FS:RS' file
KEY 4048:1736 string 3
KEY 0:1772 string 1
KEY 4192:1349 string 1
KEY 7329:2407 string 2
KEY 0:1774 string 1

Comme indiqué par Ed Morton dans les commentaires, il est préférable d’ajouter des accolades pour la sécurité et des parenthèses pour la portabilité.

awk '{ ORS = (NR%2 ? FS : RS) } 1' file

ORS représente le séparateur d'enregistrement de sortie. Ce que nous faisons ici est de tester une condition en utilisant le NR qui stocke le numéro de ligne. Si le modulo de NR est une valeur vraie (> 0), nous définissons le séparateur de champs de sortie sur la valeur de FS (séparateur de champs), qui est par défaut un espace, sinon nous affectons la valeur de RS (séparateur d'enregistrement) qui est une nouvelle ligne.

Si vous souhaitez ajouter , comme séparateur, utilisez ce qui suit:

awk '{ ORS = (NR%2 ? "," : RS) } 1' file
11
jaypal singh

Bien qu'il semble que les solutions précédentes fonctionnent, si une seule anomalie se produit dans le document, la sortie est fragmentée. Ci-dessous est un peu plus sûr.

sed -n '/KEY/{
N
s/\n/ /p
}' somefile.txt
11
J.D.

Voici ma solution en bash:

while read line1; do read line2; echo "$line1, $line2"; done < data.txt
10
Hai Vu

"ex" est un éditeur de ligne scriptable appartenant à la même famille que sed, awk, grep, etc. Je pense que c'est peut-être ce que vous recherchez. Beaucoup de clones/successeurs modernes ont également un mode vi.

 ex -c "%g/KEY/j" -c "wq" data.txt

Ceci dit pour chaque ligne, si elle correspond à "KEY", effectuez un j oin de la ligne suivante. Une fois cette commande terminée (par rapport à toutes les lignes), émettez un rite w et q uit.

7
Justin

Vous pouvez utiliser awk comme ceci pour combiner deux paires de lignes:

awk '{ if (NR%2 != 0) line=$0; else {printf("%s %s\n", line, $0); line="";} } \
     END {if (length(line)) print line;}' flle
4
anubhava

Si Perl est une option, vous pouvez essayer:

Perl -0pe 's/(.*)\n(.*)\n/$1 $2\n/g' file.txt
4
andrefs

Une légère variation sur réponse de Glenn Jackman en utilisant paste: si la valeur de l'option délimiteur -d contient plus d'un caractère, paste fait défiler les caractères un par un. un, et combiné avec les options -s continue à le faire tout en traitant le même fichier d’entrée.

Cela signifie que nous pouvons utiliser ce que nous voulons comme séparateur plus la séquence d'échappement \n pour fusionner deux lignes à la fois.

En utilisant une virgule:

$ paste -s -d ',\n' infile
KEY 4048:1736 string,3
KEY 0:1772 string,1
KEY 4192:1349 string,1
KEY 7329:2407 string,2
KEY 0:1774 string,1

et le signe dollar:

$ paste -s -d '$\n' infile
KEY 4048:1736 string$3
KEY 0:1772 string$1
KEY 4192:1349 string$1
KEY 7329:2407 string$2
KEY 0:1774 string$1

Ce que ( ne peut pas faire, c’est utiliser un séparateur composé de plusieurs caractères.

De plus, si paste est conforme à POSIX, cela ne modifiera pas la nouvelle ligne de la dernière ligne du fichier. Par conséquent, pour un fichier d'entrée avec un nombre impair de lignes comme

KEY 4048:1736 string
3
KEY 0:1772 string

paste ne collera pas sur le caractère de séparation sur la dernière ligne:

$ paste -s -d ',\n' infile
KEY 4048:1736 string,3
KEY 0:1772 string
3
Benjamin W.

Vous pouvez également utiliser la commande vi suivante:

:%g/.*/j
3
Jdamian

Une autre solution utilisant vim (juste pour référence).

Solution 1:

Ouvrir le fichier dans vim vim filename, puis exécuter la commande :% normal Jj

Cette commande est facile à comprendre:

  • %: pour toutes les lignes,
  • normal: exécute la commande normale
  • Jj: exécuter la commande Join, puis passer à la ligne ci-dessous

Après cela, sauvegardez le fichier et quittez avec :wq

Solution 2:

Exécutez la commande dans Shell, vim -c ":% normal Jj" filename, puis enregistrez le fichier et quittez avec :wq.

2
Jensen
nawk '$0 ~ /string$/ {printf "%s ",$0; getline; printf "%s\n", $0}' filename

Cela se lit comme

$0 ~ /string$/  ## matches any lines that end with the Word string
printf          ## so print the first line without newline
getline         ## get the next line
printf "%s\n"   ## print the whole line and carriage return
1
Shahab Khan

Dans le cas où je devais combiner deux lignes (pour un traitement plus facile), mais permettre aux données de dépasser le spécifique, j'ai trouvé cela utile

data.txt

string1=x
string2=y
string3
string4
cat data.txt | nawk '$0 ~ /string1=/ { printf "%s ", $0; getline; printf "%s\n", $0; getline } { print }' > converted_data.txt

la sortie ressemble alors à:

converti_données.txt

string1=x string2=y
string3
string4
1
Ben Taylor

Le plus simple est ici:

  1. Supprimez les lignes paires et écrivez-le dans un fichier temporaire 1.
  2. Supprimez les lignes impaires et écrivez-le dans un fichier temporaire 2.
  3. Combinez deux fichiers en un en utilisant la commande paste avec -d (signifie supprimer de l'espace)
sed '0~2d' file > 1 && sed '1~2d' file > 2 && paste -d " " 1 2
0
Serg
Perl -0pE 's{^KEY.*?\K\s+(\d+)$}{ $1}msg;' data.txt > data_merged-lines.txt

-0 gobe le fichier entier au lieu de le lire ligne par ligne;
pE enveloppe le code avec une boucle et affiche le résultat, voir les détails dans http://perldoc.Perl.org/perlrun.html ;
^KEY correspond à "KEY" au début de la ligne, suivi par une correspondance non gourmande de tout (.*?) avant la séquence de

  1. un ou plusieurs espaces \s+ de tout type, y compris les sauts de ligne;
  2. un ou plusieurs chiffres (\d+) que nous capturons puis réinsérons sous la forme $1;

suivi de la fin de la ligne $.

\K exclut commodément tout ce qui se trouve du côté gauche de la substitution afin que { $1} ne remplace qu'une ou deux séquences, voir http://perldoc.Perl.org/perlre.html .

0
Onlyjob

Une solution plus générale (permettant de joindre plusieurs lignes de suivi) en tant que script Shell. Cela ajoute une ligne entre chaque parce que j'avais besoin de visibilité, mais cela est facilement résolu. Cet exemple est où la ligne "clé" s'est terminée en: et aucune autre ligne ne l'a fait.

#!/bin/bash
#
# join "The rest of the story" when the first line of each   story
# matches $PATTERN
# Nice for looking for specific changes in bart output
#

PATTERN='*:';
LINEOUT=""
while read line; do
    case $line in
        $PATTERN)
                echo ""
                echo $LINEOUT
                LINEOUT="$line"
                        ;;
        "")
                LINEOUT=""
                echo ""
                ;;

        *)      LINEOUT="$LINEOUT $line"
                ;;
    esac        
done
0
Jan Parcel