Transformar string de várias linhas em uma única vírgula separada

95

Digamos que eu tenha a seguinte string:

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)

Como faço para transformar isso em simplesmente

+12.0,+15.5,+9.0,+13.5

em bash?

Alex Coplan
fonte
Vamos voltar por um momento e considerar este tópico uma acusação gritante do bash como uma linguagem de programação. Considere Scala listOfStuff mkString ", "ou Haskellintercalate ", " listOfString
FP Livremente

Respostas:

92

Você pode usar awke sed:

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

Ou se você quiser usar um cano:

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

Para dividir:

  • awk é ótimo para lidar com dados divididos em campos
  • -vORS=,define o "separador de registro de saída" para ,, que é o que você queria
  • { print $2 }diz awkpara imprimir o segundo campo para cada registro (linha)
  • file.txt é o seu nome de arquivo
  • sedapenas se livra do rastro ,e o transforma em uma nova linha (se você não quiser uma nova linha, pode fazer s/,$//)
Dan Fego
fonte
1
awk: opção -v inválida :(
Marsellus Wallace
6
Adicione um espaço entre -v e ORS =, (para mim, no osx)
Graham P Heath
Como fazer o mesmo comando para separar o tubo? awk -v ORS=| '{ print $1 }' DCMC.rtf | sed 's/,$/\n/'estou recebendo um erro
Yogesh,
2
estranhamente, quando tento fazer isso, a saída está vazia.
eternaltyro
1
Acho que para a versão encanada deveria ser de {print $1}outra forma, estou recebendo apenas vírgulas na saída
Przemysław Czechowski
162

Limpo e simples:

awk '{print $2}' file.txt | paste -s -d, -
Mattias Ahnberg
fonte
3
Esta é a melhor resposta aqui, e obviamente a maneira correta de fazer isso
forresthopkinsa de
Como faço para citar todos os valores com aspas simples / duplas?
Hussain
1
@Hussaincat thing | awk -F',' '{ print "'\''" $7 "'\' '" }' | paste -s -d ','
starbeamrainbowlabs
Como usar ,'como delimitador?
Kasun Siyambalapitiya
Lembre-se de lidar com novas linhas do Windows (por exemplo, usando dos2unix) se houver CRLFs na string.
Bowi
19
cat data.txt | xargs | sed -e 's/ /, /g'
Bhargav Srinivasan
fonte
Não funciona com linhas contendo espaços
Lukman
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
fonte
saúde, e se a entrada para awk fosse por meio de entrada padrão (basta colocar function | awk...em seu exemplo?
Alex Coplan
10

awk one liner

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

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

Isso deve funcionar também

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

Isso pode funcionar para você:

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

Para cada linha do arquivo; corte o primeiro campo e os espaços a seguir, corte o resto da linha a seguir ao segundo campo e acrescente ao espaço de espera. Exclua todas as linhas, exceto a última, onde trocamos para o espaço de espera e, após excluir a nova linha introduzida no início, converta todas as novas linhas em ,'s.

NB pode ser escrito:

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

Você pode usar grep:

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

que encontra a string começando com +, seguida por qualquer string e \S\+, a seguir, converte os caracteres da nova linha em vírgulas. Isso deve ser muito rápido para arquivos grandes.

Kenorb
fonte
4

Experimente este código fácil:

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

tente isto:

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

o bom é a parte fácil de deletar caracteres de nova linha "\ n"!

EDIT: outra ótima maneira de unir linhas em uma única linha com o sed é esta: |sed ':a;N;$!ba;s/\n/ /g'veio daqui .

Aquarius Power
fonte
Esse EDIT é incrível - +1!
JoeG
2

Uma solução escrita em 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
fonte
2

Não vi esta solução simples com awk

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

Com 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
fonte
0

Você também pode fazer isso com duas chamadas 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

A primeira chamada sed remove dados desinteressantes e a segunda junta todas as linhas.

Elias Dorneles
fonte
0

Você também pode imprimir assim:

Apenas 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

fonte
0

Outra solução Perl, semelhante ao awk de Dan Fego:

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

-a diz ao perl para dividir a linha de entrada no array @F, que é indexado a partir de 0.

Chris Koknat
fonte
0

Bem, a parte mais difícil provavelmente é selecionar a segunda "coluna", já que não conheço uma maneira fácil de tratar vários espaços como um só. De resto, é fácil. Use substituições 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
fonte