Este comando
$ tmp="$(cat tmp.csv.gz)" && echo "$tmp" | gzip -l
atribui o conteúdo de tmp.csv.gz
a uma variável shell e tenta usar echo
para canalizar isso para gzip
. Mas os recursos do shell ficam no caminho (caracteres nulos são omitidos). Você pode ver isso por um script de teste:
#!/bin/sh
tmp="$(cat tmp.csv.gz)" && echo "$tmp" |cat >foo.gz
cmp foo.gz tmp.csv.gz
e com mais algum trabalho, usando od
(ou hexdump
) e olhando de perto os dois arquivos. Por exemplo:
0000000 037 213 010 010 373 242 153 127 000 003 164 155 160 056 143 163
037 213 \b \b 373 242 k W 0000000 037 213 010 010 373 242 153 127 003 164 155 160 056 143 163 166
037 213 \b \b 373 242 k W 003 t m p . c s v
0000020 305 226 141 157 333 066 020 206 277 367 127 034 012 014 331 240
305 226 a o 333 6 020 206 277 367 W 034 \n \f 331 240
0000040 110 246 145 331 362 214 252 230 143 053 251 121 064 026 152 027
H 246 e 331 362 214 252 230 c + 251 Q 4 026 j 027
003 t m p . c s
0000020 166 000 305 226 141 157 333 066 020 206 277 367 127 034 012 014
v #!/usr/bin/perl -w
use strict;
our %counts;
sub doit() {
my $file = shift;
my $fh;
open $fh, "$file" || die "cannot open $file: $!";
my @data = <$fh>;
close $fh;
for my $n ( 0 .. $#data ) {
for my $o ( 0 .. ( length( $data[$n] ) - 1 ) ) {
my $c = substr( $data[$n], $o, 1 );
$counts{$c} += 1;
}
}
}
while ( $#ARGV >= 0 ) {
&doit( shift @ARGV );
}
for my $c ( sort keys %counts ) {
if ( ord $c > 32 && ord $c < 127 ) {
printf "%s:%d\n", $c, $counts{$c} if ( $counts{$c} );
}
else {
printf "\%03o:%d\n", ord $c, $counts{$c} if ( $counts{$c} );
}
}
305 226 a o 333 6 020 206 277 367 W 034 \n \f
0000040 331 240 110 246 145 331 362 214 252 230 143 053 251 121 064 026
331 240 H 246 e 331 362 214 252 230 c + 251 Q 4 026
elimina um nulo na primeira linha desta saída:
$ tmp="$(cat tmp.csv.gz)" && echo "$tmp" | gzip -l
Como os dados mudam, não é mais um arquivo gzip'd válido, o que produz o erro.
Como observado por @coffemug, a página de manual aponta que o gzip irá reportar um -1
para arquivos que não estão no formato gzip'd. No entanto, a entrada não é mais um arquivo compactado no formato any , de modo que a página de manual é enganosa: ela não a categoriza como tratamento de erros.
Leitura adicional:
@wildcard aponta que outros caracteres, como barra invertida, podem ser adicionados ao problema, porque algumas versões de echo
interpretarão uma barra invertida como um escape e produzirão um caractere diferente (ou não, dependendo do tratamento das fugas aplicadas a personagens não em seu repertório). Para o caso de gzip (ou a maioria das formas de compressão), os vários valores de byte são igualmente prováveis, e como todos os nulos serão omitidos, enquanto que algumas barras invertidas causarão os dados para ser modificado.
A maneira de evitar isso não é tentar atribuir uma variável shell ao conteúdo de um arquivo compactado. Se você quiser fazer isso, use uma linguagem mais adequada. Aqui está um script Perl que pode contar frequências de caracteres, como um exemplo:
#!/bin/sh
tmp="$(cat tmp.csv.gz)" && echo "$tmp" |cat >foo.gz
cmp foo.gz tmp.csv.gz