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?
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
paste
est bon pour ce travail:
paste -d " " - - < filename
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.
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:
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
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
Voici ma solution en bash:
while read line1; do read line2; echo "$line1, $line2"; done < data.txt
"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.
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
Si Perl est une option, vous pouvez essayer:
Perl -0pe 's/(.*)\n(.*)\n/$1 $2\n/g' file.txt
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
Vous pouvez également utiliser la commande vi suivante:
:%g/.*/j
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:
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
.
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
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
Le plus simple est ici:
sed '0~2d' file > 1 && sed '1~2d' file > 2 && paste -d " " 1 2
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
\s+
de tout type, y compris les sauts de ligne;(\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 .
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