
gdrivetiene un subcomando list
que imprime una lista de archivos como el siguiente ejemplo:
gdrive list
Producción:
Id Name Type Size Created
1sV3_a1ySV0-jbLxhA8NIEts1KU_aWa-5 info.pdf bin 10.0 B 2018-08-27 20:26:20
1h-j3B5OLryp6HkeyTsd9PJaAtKK_GYyl 2018-12-ss-scalettapass dir 2018-08-27 20:26:19
Estoy intentando analizar este resultado usando herramientas como awk
y sed
sin éxito.
Los problemas son 'campos' vacíos en la columna de tamaño y los anchos dinámicos de las columnas.
¿Alguien tiene una idea de cómo analizar este resultado?
Respuesta1
awk puede manejar datos de ancho fijo. Primero necesitamos determinar el ancho de las columnas:
fieldwidths=$(head -n 1 file | grep -Po '\S+\s*' | awk '{printf "%d ", length($0)}')
Este valor es "36 26 7 9 7 "
: el último campo tiene más de 7 caracteres. Hagamos arbitrariamente 70 caracteres:
fieldwidths=${fieldwidths/% /0}
Ahora, leamos los datos y convirtámoslos en CSV:
awk -v FIELDWIDTHS="$fieldwidths" '{
for (i=1; i<=NF; i++) {
val = $i
sub(/ *$/, "", val)
gsub(/"/, "\"\"", val)
printf "%s\"%s\"", (i==1 ? "" : ","), val
}
print ""
}' file
salidas:
"Id","Name","Type","Size","Created"
"1sV3_a1ySV0-jbLxhA8NIEts1KU_aWa-5","info.pdf","bin","10.0 B","2018-08-27 20:26:20"
"1h-j3B5OLryp6HkeyTsd9PJaAtKK_GYyl","2018-12-ss-scalettapass","dir","","2018-08-27 20:26:19"
La misma funcionalidad con perl.
perl -lne '
if ($. == 1) {
@head = ( /(\S+\s*)/g );
pop @head;
$patt = "^";
$patt .= "(.{" . length($_) . "})" for @head;
$patt .= "(.*)\$";
}
print join ",", map {s/"/""/g; s/\s+$//; qq("$_")} (/$patt/o);
' file
Respuesta2
Puede hacer esto Perl
usando la unpack
función creando la plantilla de descompresión dinámicamente examinando el encabezado (primera línea):
perl -lpe '
$fmt //= join "", map("A" . length(), /\H+\h+(?=\H)/g), "A*";
$_ = join ",", map { s/"/""/gr =~ s/(.*)/"$1"/r } unpack $fmt;
' input-file.txt
Explicación:
-p
hará queperl
se consuma el archivo por línea. Cada línea, también conocida como registro, se denomina$_
. Otro efecto-p
es que imprime automáticamente el registro actual antes de buscar el siguiente.-l
hace 2 cosas, estableceORS = RS = \n
- La expresión regular
/\H+\h+(?=\H)/g
buscará todos los campos excepto el último y luego estos se enviarán amap
. map
calcula las longitudes de estos campos y antepone una "A" a cada uno.- En lugar de no seleccionar el último campo anterior, agregamos una "A*" general.
- Luego, estos se pasan a
join
quien los une en una cadena usando el delimitador nulo. Entonces, el formato de descomprimir está listo para usar y no se vuelve a calcular debido al//=
operador que es ladefined-or
función. - Ahora, armados con el formato de descomprimir creado dinámicamente, procedemos a aplicarlo a cada línea, incluido el encabezado.
unpack
descomprime una cadena, en nuestro caso la línea actual, usando el formato proporcionado y emite campos desempaquetados.- Estos campos emitidos luego se ingresan,
map
que opera en cada uno uno por uno y realiza los pasos descritos en el{ ... }
código. En nuestro caso, en cada campo hacemos lo siguiente: a) duplicar las comillas dobles. b) cubra el campo con comillas dobles. - Una vez que
map
termina de editar los campos, los envía ajoin
, que los une usando la coma,
para formar un pequeño archivo agradableCSV
. - PD:Tenga en cuenta que no tuvimos que recortar los espacios en blanco finales en los campos generados por
unpack
, porqueunpack
lo hace por usted cuando usa elA
carácter de formato (A para ASCII).
Producción:
"Id","Name","Type","Size","Created"
"1sV3_a1ySV0-jbLxhA8NIEts1KU_aWa-5","info.pdf","bin","10.0 B","2018-08-27 20:26:20"
"1h-j3B5OLryp6HkeyTsd9PJaAtKK_GYyl","2018-12-ss-scalettapass","dir","","2018-08-27 20:26:19"
Esto lo puede hacer la sed
herramienta, pero necesitaría un enfoque de dos pasos, en el que primero, usando la línea de encabezado de la entrada, generamos un sed
script dinámicamente, que luego opera sobre el archivo de entrada (incluido también el encabezado) para realice la operación deseada, como se muestra:
if="input-file.txt"
cmd=$(< "$if" head -n 1 | perl -lne 'print join $/, reverse map { $s += length();qq[s/./\\n/$s] } /\H+\h+(?=\H)/g')
sed -e '
'"${cmd}"'
s/"/""/g
s/[[:blank:]]*\n/","/g
s/.*/"&"/
' < "$if"