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?


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/,$//)

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, -

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


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

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

8

Esto también debería funcionar

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

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

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.


4

Prueba este sencillo código:

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

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í .


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


2

No veo esta sencilla solución con awk

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

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

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.


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

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.


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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.