Não há erro com head -n 2
; Você pode verificar isso removendo o |
e o código subseqüente.
O problema é que o código entre as chaves só é executado uma vez - não é um loop. E read
só lê dados de uma única linha de entrada. Então você precisa fazer algum tipo de loop para imprimir dados para vários arquivos.
Você pode usar um loop while
ou aproveitar o loop integrado do awk para ler & imprima os dados. Por exemplo, o comando awk abaixo apenas imprime as informações de tamanho se o tamanho do arquivo atual for diferente do tamanho do arquivo anterior.
awk 'BEGIN{size=-1}; {if($1!=size){size=$1; printf "size: %d\n", size}; printf "\t%s\n", $2}'
Não precisamos realmente inicializar explicitamente size
, pois ele é inicializado automaticamente para a sequência vazia, mas é bom ser explícito sobre essas coisas, IMHO.
Esse comando do awk substitui o
{
read -r file dir
printf "size: %d\n\t%s\n" "$file" "$dir"
}
seção do seu código. Em outras palavras, você pode usar
find "$dir" -type f -printf '%s %p\n' |
sort -n -r | head -n 2 |
awk 'BEGIN{size=-1};
{if($1!=size){size=$1; printf "size: %d\n", size};
printf "\t%s\n", $2}'
Você pode colocar tudo em uma linha ou dividi-lo em várias linhas. Também é possível colocar o programa awk em seu próprio arquivo, mas não há necessidade de fazer isso para um programa tão pequeno.
Observe que você pode tornar a opção -n
em head
tão grande quanto desejar e o programa awk se comportará como esperado. Observe também que o awk é muito rápido - é muito mais eficiente do que usar read
e printf
.
FWIW, código awk para processamento de texto simples é frequentemente mais rápido que código Python equivalente, então mesmo que muitos considerem o awk antiquado ainda é bastante popular.
Para imprimir os dados para somente o (s) maior (s) arquivo (s) em um diretório, você pode fazer isso:
find . -type f -printf '%s %p\n' |
sort -nr |
awk 'NR==1{size=$1;printf "size: %d\n", size};
$1!=size{exit};
{printf "\t%s\n", $2}'
O NR==1
diz para executar o seguinte bloco (o material dentro do {}
) somente quando o Número do Registro for igual a 1 - um registro é apenas uma linha. Assim, obtemos o tamanho do primeiro arquivo, que é o maior arquivo (graças ao comando sort
anterior), salve-o na variável size
e imprima o tamanho.
$1!=size{exit}
diz para sair do programa assim que lermos uma linha em que os dados no primeiro campo não correspondem ao que salvamos na variável size
.
O último bloco {printf "\t%s\n", $2}
imprime o nome do caminho de cada arquivo.
Existem várias maneiras de imprimir os arquivos maiores e menores encontrados pelo comando find
. Uma maneira seria ler todos os dados no awk, armazená-los em uma matriz, classificar a matriz e, em seguida, imprimir os dados para os arquivos de no máximo & tamanho mínimo. Mas vou adotar uma estratégia mais simples aqui e reciclar meu código existente. Para fazer isso de maneira mais eficiente, colocarei o programa awk em um arquivo. Salve este arquivo em um diretório em seu comando PATH e conceda a ele permissão de execução.
field1match.awk
#!/usr/bin/awk -f
# print only the records whose 1st field matches that of the 1st record
# Written by PM 2Ring 2015.05.21
NR==1{size=$1; printf "size: %d\n", size}
$1!=size{exit}
{printf "\t%s\n", $2}
E aqui está a linha de comando que usa tee
para duplicar a saída de find
e, em seguida, classificá-la e imprimi-la usando a substituição de processo:
find "$dir" -type f -printf '%s %p\n' |
tee > >(sort -n | field1match.awk) >(sort -rn | field1match.awk)