¿Cómo puedo convertir datos delimitados por tabulaciones en datos delimitados por comas?

8

Estoy solicitando una lista de instantáneas ec2 a través de la herramienta de línea de comando ec2 de amazon:

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

Los datos se parecen a esto:

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

¿Cómo puedo interceptar los datos antes de redirigirlos snapshots.csvy hacer lo siguiente?

  • reemplazar "pestañas" con comas
  • encapsular valores con citas
  • si un valor es todos números, agregue un prefijo con un =símbolo para que Excel lo trate como texto; por ejemplo, OwnerIddebe ser "=5098939"(este no es necesario si no se puede hacer en línea y en su lugar requeriría un archivo o función de script)

salida deseada:

"SnapshotId","VolumeId","StartTime","OwnerId","VolumeSize","Description"
"snap-00b66464","vol-b99a38d0","2012-01-05","=5098939","=160","my backup"
cwd
fuente
Aquí es donde alguien le dice que importe utilizando pestañas. O lo harían, si Excel no estuviera en crack.
Ignacio Vazquez-Abrams
Sí, estoy tratando de ayudar a sobresalir un poco, ya que no parece estar tan bien por sí solo. También es bueno tener un archivo CSV que se puede abrir en lugar de tener que usar el comando de menú de importación. Ya intenté cambiar la extensión a ".tsv" sin suerte.
cwd
Creo que su salida deseada está un poco apagada. Tiene muchos campos vacíos allí (las comillas vacías).
Patrick

Respuestas:

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
}

Suponiendo que nombre esto convert.awk, puede llamar con

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

o (después de agregar permisos de ejecución chmod a+x convert.awk)

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

Esto creará una nueva columna para cada pestaña, que mantendrá la columna de comentarios juntos (a menos que contenga pestañas), pero agregará columnas vacías (aunque así es como se ve su salida de muestra, por lo que tal vez realmente quiera eso). Si desea dividir en todos los espacios en blanco (esto colapsará pestañas adicionales dentro de la tabla pero pondrá cada palabra en la descripción como una nueva columna), saque la FS="\t";declaración.

Para las generaciones futuras, si no necesita el "s o =s o el espacio en blanco incrustado, puede hacerlo de una sola línea:

awk -v OFS=, '{$1=$1;print}'
Kevin
fuente
Buena solución limpia. Pensé que terminaría mucho más feo que eso, pero no soy una persona horrible :-)
Patrick
./convert.shEntonces, ¿guardo esto en un archivo como , chmod + x, y luego canalizo la entrada para que imprima la salida? Estoy consiguiendo un error: /usr/bin/awk: syntax error at source line 1 context is >>> . <<< /convert.sh.
cwd
@cwd Puede guardarlo en un archivo, le sugiero convert.awkque indique que es un awkscript y no bashuno. Actualicé la publicación con la línea de comando completa y noté que agregué una -fbandera que había olvidado a la primera línea (que le dice que interprete el archivo como comandos).
Kevin
La versión de una línea trata cualquier espacio en blanco como un separador de campo, no solo pestañas. Necesita una -F '\ t' antes de -V.
Paul_Pedant
4

Aquí hay una solución perl. Esto podría ser posible con sed / awk, pero la prueba de la parte numérica probablemente lo haría bastante feo.

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
Patricio
fuente
3

Si solo eres flojo como yo y quieres hacerlo todo en una línea de comando sin escribir un script, así es como lo haría.

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

El ^Ise hace presionando ctrl+ v i.

El primero sedcambia todo tabspor ",". El segundo sedinserta un "al principio de cada línea, y el último sed inserta un cierre "al final de cada línea.

Tim Kennedy
fuente
¿Cómo conseguiste que ctrl + vi apareciera así?
Burhan Khalid
@burhan La sintaxis es <kbd>text</kbd>.
jw013
3
O en una línea: sed -e 's/^I/","/g' -e 's/.*/"&"/'o incluso más corta sed -e 's/^I/","/g;s/.*/"&"/'.
Arcege
3

Otra solución de 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 con ec2-describe-snapshots -H --hide-tags | /var/tmp/script.pl > output.txt

Jim
fuente
Scalar :: Util no es un módulo externo, viene con perl estándar.
Patrick
Cierto. Disculpas por redactar mal mi comentario previsto. Gracias por la corrección.
Jim
1

sed es la utilidad de Linux más útil que he encontrado.

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

El primer comando reemplaza todas las pestañas en cada línea con comas y comillas. El segundo comando inserta comillas al principio y al final de cada línea, de modo que cada valor estará rodeado de comillas, lo que permite que las comas sean parte del valor.

Pablo
fuente
0

Esto podría funcionar para usted:

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