
gdrivepossui um subcomando list
que imprime uma lista de arquivos como o exemplo a seguir:
gdrive list
Saída:
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
Estou tentando analisar essa saída usando ferramentas como awk
e sed
sem sucesso.
Os problemas são 'campos' vazios na coluna de tamanho e nas larguras dinâmicas das colunas.
Alguém tem uma idéia de como analisar essa saída?
Responder1
awk pode lidar com dados de largura fixa. Primeiro precisamos determinar as larguras das colunas:
fieldwidths=$(head -n 1 file | grep -Po '\S+\s*' | awk '{printf "%d ", length($0)}')
Este valor é "36 26 7 9 7 "
-- o último campo tem mais de 7 caracteres. Vamos arbitrariamente ter 70 caracteres:
fieldwidths=${fieldwidths/% /0}
Agora, vamos ler os dados e transformá-los em 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
saídas:
"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"
A mesma funcionalidade com 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
Responder2
Você pode fazer isso Perl
usando a unpack
função criando o modelo de descompactação dinamicamente examinando o cabeçalho (1ª linha):
perl -lpe '
$fmt //= join "", map("A" . length(), /\H+\h+(?=\H)/g), "A*";
$_ = join ",", map { s/"/""/gr =~ s/(.*)/"$1"/r } unpack $fmt;
' input-file.txt
Explicação:
-p
faráperl
consumir o arquivo por linha. Cada linha, também conhecida como registro, é chamada de$_
. Outro efeito-p
é imprimir automaticamente o registro atual antes de buscar o próximo.-l
faz 2 coisas, conjuntosORS = RS = \n
- A regex
/\H+\h+(?=\H)/g
deve buscar todos os campos, exceto o último, e então estes são alimentadosmap
. map
calcula os comprimentos desses campos e prefixa um "A" para cada um.- Em vez de não selecionar o último campo acima, adicionamos um "A*" genérico.
- Eles são então passados para
join
o qual os une em uma string usando o delimitador nulo. Portanto, o formato unpack está pronto para uso e não é computado novamente por causa do//=
operador que é adefined-or
função. - Agora, armados com o formato de descompactação criado dinamicamente, aplicamos a cada linha, incluindo o cabeçalho.
unpack
descompacta uma string, no nosso caso a linha atual, usando o formato fornecido e emite campos descompactados.- Esses campos emitidos são então inseridos,
map
os quais operam um por um e executam as etapas descritas no{ ... }
código. No nosso caso, em cada campo fazemos o seguinte: a) duplicar as aspas duplas. b) coloque o campo entre aspas duplas. - Depois de
map
terminar a edição dos campos, ele os lança parajoin
, que os une usando a vírgula,
para formar um pequenoCSV
arquivo. - PS:Observe que não tivemos que cortar os espaços em branco nos campos gerados por
unpack
, porque,unpack
faz isso para você ao usar oA
caractere de formatação (A para ASCII).
Saída:
"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"
Isso pode ser feito pela sed
ferramenta, mas precisaria de uma abordagem de duas passagens, em que primeiro, usando a linha de cabeçalho da entrada, geramos um sed
script dinamicamente, que então opera sobre o arquivo de entrada (incluindo também o cabeçalho) para execute a operação desejada, conforme mostrado:
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"