Convertir una cadena de varias líneas en una única separada por comas

96

Digamos que tengo la siguiente cadena:

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)

¿Cómo puedo convertir eso en simplemente

+12.0,+15.5,+9.0,+13.5

en bash?

Alex Coplan
fuente
Retrocedamos un momento y consideremos este hilo como una acusación flagrante de bash como lenguaje de programación. Considere Scala listOfStuff mkString ", "o Haskellintercalate ", " listOfString
FP libremente

Respuestas:

92

Puede utilizar awky sed:

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

O si quieres usar una pipa:

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

Para desglosarlo:

  • awk es excelente para manejar datos desglosados ​​en campos
  • -vORS=,establece el "separador de registros de salida" en ,, que es lo que deseaba
  • { print $2 }dice awkque imprima el segundo campo para cada registro (línea)
  • file.txt es tu nombre de archivo
  • sedsimplemente se deshace del final ,y lo convierte en una nueva línea (si no desea una nueva línea, puede hacerlo s/,$//)
Dan Fego
fuente
1
awk: opción -v no válida :(
Marsellus Wallace
6
Agregue un espacio entre -v y ORS =, (para mí, en osx)
Graham P Heath
¿Cómo hacer el mismo comando para separar la tubería? awk -v ORS=| '{ print $1 }' DCMC.rtf | sed 's/,$/\n/'Recibo un error
Yogesh
2
extrañamente, cuando trato de hacer esto, la salida está vacía.
eternaltyro
1
Creo que para la versión canalizada debería ser de lo {print $1}contrario, solo obtengo comas en la salida
Przemysław Czechowski
163

Limpio y simple:

awk '{print $2}' file.txt | paste -s -d, -
Mattias Ahnberg
fuente
3
Esta es la mejor respuesta aquí, y obviamente la forma correcta de hacer esto
forresthopkinsa
¿Cómo cito todos los valores con comillas simples / dobles?
Hussain
2
@Hussaincat thing | awk -F',' '{ print "'\''" $7 "'\' '" }' | paste -s -d ','
starbeamrainbowlabs
¿Cómo se usa ,'como delimitador?
Kasun Siyambalapitiya
Recuerde manejar las nuevas líneas de Windows (por ejemplo, usando dos2unix) si hay CRLF en la cadena.
Bowi
19
cat data.txt | xargs | sed -e 's/ /, /g'
Bhargav Srinivasan
fuente
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
fuente
salud, ¿qué pasa si la entrada a awk fue a través de la entrada estándar (solo ponga function | awk...su ejemplo?
Alex Coplan
10

awk una línea

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

+12.0,+15.5,+9.0,+13.5
Rahul Verma
fuente
8

Esto también debería funcionar

awk '{print $2}' file | sed ':a;{N;s/\n/,/};ba'
Jaypal Singh
fuente
8

Esto podría funcionar para ti:

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

o

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

o

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

Para cada línea del archivo; corte el primer campo y los espacios siguientes, corte el resto de la línea que sigue al segundo campo y añádalo al espacio de espera. Elimina todas las líneas excepto la última donde cambiamos al espacio de espera y después de eliminar la nueva línea introducida al principio, convertimos todas las líneas nuevas en ,'s.

NB Podría escribirse:

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

Puede utilizar grep:

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

que encuentra la cadena que comienza con +, seguida de cualquier cadena \S\+, luego convierte los caracteres de nueva línea en comas. Esto debería ser bastante rápido para archivos grandes.

Kenorb
fuente
4

Prueba este sencillo código:

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

prueba esto:

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

¡Lo bueno es la parte fácil de eliminar caracteres de nueva línea "\ n"!

EDITAR: otra excelente manera de unir líneas en una sola línea con sed es esta: |sed ':a;N;$!ba;s/\n/ /g'obtenido desde aquí .

Poder de Acuario
fuente
Esa EDITAR es increíble - ¡+1!
JoeG
2

Una solución escrita en puro 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[*]}")

Resultado: + 12.0, + 15.5, + 9.0, + 13.5

Quatro por Quatro
fuente
2

No veo esta sencilla solución con awk

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

Con 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
fuente
0

También puedes hacerlo con dos llamadas 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

La primera llamada sed elimina los datos poco interesantes y la segunda une todas las líneas.

Elias Dorneles
fuente
0

También puede imprimir así:

Solo awk: usando 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

fuente
0

Otra solución de Perl, similar al awk de Dan Fego:

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

-a le dice a perl que divida la línea de entrada en la matriz @F, que está indexada a partir de 0.

Chris Koknat
fuente
0

Bueno, la parte más difícil probablemente sea seleccionar la segunda "columna", ya que no conocería una manera fácil de tratar varios espacios como uno solo. Por lo demás, es fácil. Usa sustituciones de 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
fuente