Transformer une chaîne multiligne en une seule virgule séparée

95

Disons que j'ai la chaîne suivante:

something1:    +12.0   (some unnecessary trailing data (this must go))
something2:    +15.5   (some more unnecessary trailing data)
something4:    +9.0   (some other unnecessary data)
something1:    +13.5  (blah blah blah)

Comment puis-je transformer cela en simplement

+12.0,+15.5,+9.0,+13.5

en bash?

Alex Coplan
la source
Revenons un instant en arrière et considérons ce fil comme une accusation flagrante de bash en tant que langage de programmation. Considérez Scala listOfStuff mkString ", "ou Haskellintercalate ", " listOfString
FP Librement

Réponses:

92

Vous pouvez utiliser awket sed:

awk -vORS=, '{ print $2 }' file.txt | sed 's/,$/\n/'

Ou si vous souhaitez utiliser un tuyau:

echo "data" | awk -vORS=, '{ print $2 }' | sed 's/,$/\n/'

Pour le décomposer:

  • awk est excellent pour gérer des données décomposées en champs
  • -vORS=,définit le "séparateur d'enregistrement de sortie" sur ,, ce que vous vouliez
  • { print $2 }dit awkd'imprimer le deuxième champ pour chaque enregistrement (ligne)
  • file.txt est votre nom de fichier
  • sedse débarrasse simplement de la fin ,et le transforme en une nouvelle ligne (si vous ne voulez pas de nouvelle ligne, vous pouvez le faire s/,$//)
Dan Fego
la source
1
awk: option -v invalide :(
Marsellus Wallace
6
Ajouter un espace entre -v et ORS =, (pour moi, sur osx)
Graham P Heath
Comment faire la même commande pour séparer les tuyaux? awk -v ORS=| '{ print $1 }' DCMC.rtf | sed 's/,$/\n/'je reçois une erreur
Yogesh
2
étrangement, lorsque j'essaye de faire cela, la sortie est vide.
eternaltyro
1
Je pense que pour la version avec piped, cela devrait être {print $1}sinon je n'obtiens que des virgules en sortie
Przemysław Czechowski
162

Propre et simple:

awk '{print $2}' file.txt | paste -s -d, -
Mattias Ahnberg
la source
3
C'est la meilleure réponse ici, et évidemment la bonne façon de le faire
forresthopkinsa
Comment citer toutes les valeurs avec des guillemets simples / doubles?
Hussain
1
@Hussaincat thing | awk -F',' '{ print "'\''" $7 "'\' '" }' | paste -s -d ','
starbeamrainbowlabs
Comment l'utiliser ,'comme délimiteur?
Kasun Siyambalapitiya
N'oubliez pas de gérer les sauts de ligne Windows (par exemple en utilisant dos2unix) s'il y a des CRLF dans la chaîne.
Bowi le
19
cat data.txt | xargs | sed -e 's/ /, /g'
Bhargav Srinivasan
la source
10
$ awk -v ORS=, '{print $2}' data.txt | sed 's/,$//'
+12.0,+15.5,+9.0,+13.5

$ cat data.txt | tr -s ' ' | cut -d ' ' -f 2 | tr '\n' ',' | sed 's/,$//'
+12.0,+15.5,+9.0,+13.5
kev
la source
bravo, qu'en est-il si l'entrée à awk se fait via une entrée standard (il suffit de mettre function | awk...votre exemple?
Alex Coplan
10

awk une doublure

$ awk '{printf (NR>1?",":"") $2}' file

+12.0,+15.5,+9.0,+13.5
Rahul Verma
la source
8

Cela devrait fonctionner aussi

awk '{print $2}' file | sed ':a;{N;s/\n/,/};ba'
jaypal singh
la source
8

Cela pourrait fonctionner pour vous:

cut -d' ' -f5 file | paste -d',' -s
+12.0,+15.5,+9.0,+13.5

ou

sed '/^.*\(+[^ ]*\).*/{s//\1/;H};${x;s/\n/,/g;s/.//p};d' file
+12.0,+15.5,+9.0,+13.5

ou

sed 's/\S\+\s\+//;s/\s.*//;H;$!d;x;s/.//;s/\n/,/g' file

Pour chaque ligne du fichier; coupez le premier champ et les espaces suivants, coupez le reste de la ligne suivant le deuxième champ et ajoutez à l'espace d'attente. Supprimez toutes les lignes sauf la dernière où nous basculons vers l'espace d'attente et après avoir supprimé la nouvelle ligne introduite au début, convertissez toutes les nouvelles lignes en ,'s.

NB Pourrait être écrit:

sed 's/\S\+\s\+//;s/\s.*//;1h;1!H;$!d;x;s/\n/,/g' file
potong
la source
4

Vous pouvez utiliser grep:

grep -o "+\S\+" in.txt | tr '\n' ','

qui trouve la chaîne commençant par +, suivie de n'importe quelle chaîne \S\+, puis convertit les caractères de nouvelle ligne en virgules. Cela devrait être assez rapide pour les gros fichiers.

Kenorb
la source
4

Essayez ce code simple:

awk '{printf("%s,",$2)}' File1
Vonton
la source
3

essaye ça:

sedSelectNumbers='s".* \(+[0-9]*[.][0-9]*\) .*"\1,"'
sedClearLastComma='s"\(.*\),$"\1"'
cat file.txt |sed "$sedSelectNumbers" |tr -d "\n" |sed "$sedClearLastComma"

la bonne chose est la partie facile de la suppression des caractères de nouvelle ligne "\ n"!

EDIT: un autre excellent moyen de joindre des lignes en une seule ligne avec sed est celui-ci: |sed ':a;N;$!ba;s/\n/ /g'obtenu d' ici .

Puissance du Verseau
la source
Cet EDIT est génial - +1!
JoeG
2

Une solution écrite en pur Bash:

#!/bin/bash

sometext="something1:    +12.0   (some unnecessary trailing data (this must go))
something2:    +15.5   (some more unnecessary trailing data)
something4:    +9.0   (some other unnecessary data)
something1:    +13.5  (blah blah blah)"

a=()
while read -r a1 a2 a3; do
    # we can add some code here to check valid values or modify them
    a+=("${a2}")
done <<< "${sometext}"
# between parenthesis to modify IFS for the current statement only
(IFS=',' ; printf '%s: %s\n' "Result" "${a[*]}")

Résultat: + 12,0, + 15,5, + 9,0, + 13,5

Quatro par Quatro
la source
2

Je n'ai pas vu cette solution simple avec awk

awk 'b{b=b","}{b=b$2}END{print b}' infile
ctac_
la source
0

Avec perl:

fg@erwin ~ $ perl -ne 'push @l, (split(/\s+/))[1]; END { print join(",", @l) . "\n" }' <<EOF
something1:    +12.0   (some unnecessary trailing data (this must go))
something2:    +15.5   (some more unnecessary trailing data)
something4:    +9.0   (some other unnecessary data)
something1:    +13.5  (blah blah blah)
EOF

+12.0,+15.5,+9.0,+13.5
fge
la source
0

Vous pouvez également le faire avec deux appels sed:

$ cat file.txt 
something1:    +12.0   (some unnecessary trailing data (this must go))
something2:    +15.5   (some more unnecessary trailing data)
something4:    +9.0   (some other unnecessary data)
something1:    +13.5  (blah blah blah)
$ sed 's/^[^:]*: *\([+0-9.]\+\) .*/\1/' file.txt | sed -e :a -e '$!N; s/\n/,/; ta'
+12.0,+15.5,+9.0,+13.5

Le premier appel sed supprime les données inintéressantes, et le second joint toutes les lignes.

Elias Dorneles
la source
0

Vous pouvez également imprimer comme ceci:

Just awk: utiliser printf

bash-3.2$ cat sample.log
something1:    +12.0   (some unnecessary trailing data (this must go))
something2:    +15.5   (some more unnecessary trailing data)
something4:    +9.0   (some other unnecessary data)
something1:    +13.5  (blah blah blah)

bash-3.2$ awk ' { if($2 != "") { if(NR==1) { printf $2 } else { printf "," $2 } } }' sample.log
+12.0,+15.5,+9.0,+13.5

la source
0

Une autre solution Perl, similaire à awk de Dan Fego:

perl -ane 'print "$F[1],"' file.txt | sed 's/,$/\n/'

-a dit à perl de diviser la ligne d'entrée dans le tableau @F, qui est indexé à partir de 0.

Chris Koknat
la source
0

Eh bien, la partie la plus difficile est probablement de sélectionner la deuxième "colonne" car je ne connais pas un moyen facile de traiter plusieurs espaces comme un seul. Pour le reste, c'est facile. Utilisez des substitutions bash.

# cat bla.txt
something1:    +12.0   (some unnecessary trailing data (this must go))
something2:    +15.5   (some more unnecessary trailing data)
something4:    +9.0   (some other unnecessary data)
something1:    +13.5  (blah blah blah)

# cat bla.sh
OLDIFS=$IFS
IFS=$'\n'
for i in $(cat bla.txt); do
  i=$(echo "$i" | awk '{print $2}')
  u="${u:+$u, }$i"
done
IFS=$OLDIFS
echo "$u"

# bash ./bla.sh
+12.0, +15.5, +9.0, +13.5
Marki
la source