Como converter dados delimitados por tabulação em dados delimitados por vírgula?

8

Estou solicitando uma lista de instantâneos ec2 por meio da ferramenta de linha de comando ec2 da amazon:

ec2-describe-snapshots -H --hide-tags > snapshots.csv

Os dados são mais ou menos assim:

SnapshotId      VolumeId        StartTime   OwnerId         VolumeSize  Description
snap-00b66464   vol-b99a38d0    2012-01-05  5098939         160         my backup

Como posso interceptar os dados antes de redirecioná-los para snapshots.csve fazer o seguinte:

  • substituir "guias" por vírgulas
  • encapsular valores com cotações
  • se um valor é todos os números, prefixe-o com um =para que o Excel o trate como texto - por exemplo, OwnerIddeve ser "=5098939"(este não é necessário se não puder ser feito em linha e exigiria um arquivo ou função de script)

saída desejada:

"SnapshotId","VolumeId","StartTime","OwnerId","VolumeSize","Description"
"snap-00b66464","vol-b99a38d0","2012-01-05","=5098939","=160","my backup"
cwd
fonte
É aqui que alguém diz para você importar usando guias. Ou, se o Excel não estivesse no crack.
Ignacio Vazquez-Abrams
Sim, estou tentando ajudar a se destacar um pouco, pois não parece estar tão quente por si só. Também é bom ter um arquivo CSV que possa ser aberto em vez de usar o comando de menu de importação. Eu já tentei mudar a extensão para ".tsv" sem sorte.
Cwd
Eu acho que a saída desejada está um pouco fora. Você tem muitos campos vazios lá (as aspas vazias).
Patrick

Respostas:

10
#!/usr/bin/awk -f

BEGIN { FS = "\t"; OFS = "," }
{
    for(i = 1; i <= NF; i++) {
        if ($i + 0 == $i) { $i = "=" $i }
        else gsub(/"/, "\"\"", $i);
        $i = "\"" $i "\""
    }
    print
}

Supondo que você nomeie isso convert.awk, você pode ligar com

ec2-describe-snapshots -H --hide-tags | awk -f convert.awk > snapshots.csv

ou (após adicionar permissões de execução chmod a+x convert.awk)

ec2-describe-snapshots -H --hide-tags | ./convert.awk > snapshots.csv

Isso criará uma nova coluna para cada guia, que manterá a coluna de comentários (a menos que contenha guias), mas adicione colunas vazias (embora seja a aparência da saída de amostra, talvez você realmente queira isso). Se você deseja dividir em todos os espaços em branco (isso reduzirá as guias extras na tabela, mas colocará cada palavra na descrição como uma nova coluna), retire a FS="\t";instrução.

Para as gerações futuras, se você não precisar dos "s ou =s ou espaços em branco incorporado, você pode torná-lo um one-liner:

awk -v OFS=, '{$1=$1;print}'
Kevin
fonte
Solução limpa e agradável. Pensei que iria acabar uma feia muito do que isso, mas então eu não sou uma pessoa awk :-)
Patrick
então eu salvei isso em um arquivo como ./convert.shchmod + xe canalize a entrada para que ele imprima a saída? Estou recebendo um erro: /usr/bin/awk: syntax error at source line 1 context is >>> . <<< /convert.sh.
Cwd
@cwd Você pode salvá-lo em um arquivo, sugiro convert.awkque seja um awkscript e não bashum. Atualizei a postagem com a linha de comando completa e notei que adicionei um -fsinalizador que havia esquecido à primeira linha (que diz para ele interpretar o arquivo como comandos).
Kevin
A versão de uma linha trata qualquer espaço em branco como um separador de campos, não apenas como guias. Precisa de -F '\ t' antes de -V.
Paul_Pedant 19/02
4

Aqui está uma solução perl. Isso pode ser possível com o sed / awk, mas o teste da parte numérica provavelmente a tornaria muito feia.

ec2-describe-snapshots -H --hide-tags | \
perl -e 'use Scalar::Util qw(looks_like_number);
         while (chomp($line = <STDIN>)) {
             print(join(",", map { "\"" . (looks_like_number($_) ? "=$_" :
                                           do {s/"/""/g; $_}) . "\"" }
             split(/\t/, $line)) . "\n");
         }' \
> snapshots.csv
Patrick
fonte
3

Se você é apenas preguiçoso como eu e quer fazer tudo em uma linha de comando sem escrever um script, eis como eu faria isso.

ec2-describe-snapshots -H --hide-tags | sed -e 's/^I/","/g' | sed -e 's/^/"/' | sed -e 's/$/"/'> snapshots.csv

O ^Ié feito pressionando ctrl+ v i.

O primeiro sedtroca todo o tabsfor ",". O segundo sedinsere a "no início de cada linha e o último sed insere um fechamento "no final de cada linha.

Tim Kennedy
fonte
Como você conseguiu que o ctrl + vi aparecesse assim?
precisa saber é o seguinte
@burhan A sintaxe é <kbd>text</kbd>.
Jw013
3
Ou em uma linha: sed -e 's/^I/","/g' -e 's/.*/"&"/'ou ainda mais curta sed -e 's/^I/","/g;s/.*/"&"/'.
Arcege 7/01/12
3

Outra solução Perl:

#!/usr/bin/perl -wln
use strict;

my($n,$s);chomp();
for $s ( split(/\t/,$_) )
{
    $s = '='.$s if ($s =~ /^\d+$/);
    $n.= '"'.$s.'",';
}
$n =~ s/(.*),/$1/;print $n;

invocar com ec2-describe-snapshots -H --hide-tags | /var/tmp/script.pl > output.txt

Jim
fonte
Scalar :: Util não é um módulo externo, ele vem com o perl padrão.
Patrick
Verdade. Desculpas por escrever mal o meu comentário pretendido. Obrigado pela correção.
Jim
1

sed é o utilitário linux mais útil que eu já encontrei.

sed 's/\t/","/g' TabSeparatedValues.txt > CommaSeparatedValues.csv
sed -i 's/.*/"&"/' CommaSeparatedValues.csv

O primeiro comando substitui todas as guias em cada linha por vírgulas e aspas. O segundo comando insere aspas no início e no final de cada linha, de modo que cada valor fique entre aspas, o que permite que vírgulas façam parte do valor.

Paulo
fonte
0

Isso pode funcionar para você:

sed 's/\t\+/,/g;s/^\|$/"/g;s/,/"&"/g;s/"\([0-9]\+\)"/"=\1"/g' file
potong
fonte