ls -AlhF /usr | awk '{print "echo "$6" "$7" "$8" 1 "$9" $(du -s /usr/"$9")" }' | sh
Construa um comando echo e du com o awk e, em seguida, execute-o através da tubulação para sh.
Eu desejo listar diretórios enquanto calculo seu tamanho e imprimo tudo em um comando simples, usando ls e awk , um ótimo trabalho para controlar a lista e o que eu deseja exibir:
ls -AlhF /usr | awk '{print $6, $7, $8, "1", $9 }'
Mas eu gostaria de ir um pouco mais longe e para obter o tamanho das pastas ou dos arquivos, use $ 9 com o comando du -s com algo parecido com isto:
ls -AlhF /usr | awk '{print $6, $7, $8, "1", $9, du -s /usr/$9 }'
Eu tentei muitas maneiras de escrever, com backticks, doublequote, mas sempre acabo com erros ou resultados indesejados.
ls -AlhF /usr | awk '{print "echo "$6" "$7" "$8" 1 "$9" $(du -s /usr/"$9")" }' | sh
Construa um comando echo e du com o awk e, em seguida, execute-o através da tubulação para sh.
Para responder à pergunta e ignorar os problemas de análise da saída de ls
por enquanto, para obter a saída (stdout) de um comando em awk
, faça:
cmd="that command"
output=""
while ((cmd | getline line) > 0)
output = output line RS
status = close(cmd)
Como o status de saída é codificado na variável status varia de uma implementação awk
para a próxima. Tudo em que você pode confiar é que será 0 se e somente se cmd
for bem-sucedido.
getline
inicia um shell (geralmente um shell POSIX, mas em alguns sistemas, que poderia ser um shell Bourne) para analisar essa linha de comando. Por isso, é importante citar corretamente os dados lá. Melhor é usar aspas simples, que é o mais seguro.
Aqui, como a saída será uma única linha de qualquer maneira (sua abordagem não pode manipular nomes de arquivo com nenhum caractere de espaçamento, e muito menos novas linhas), você precisa fazer apenas uma getline
:
awk -v q="'" '
function shquote(s) {
gsub(q, q "\" q q, s)
return q s q
}
{
cmd = "du -sk " shquote("/usr/" $9)
cmd | getline du_output
status = close(cmd)
}'
Se você chamar getline
sem um nome de variável, ele define $0
, o que pode facilitar a extração do uso do disco:
DIR=/usr export DIR
LC_ALL=C ls -l -- "$DIR" | awk -v q="'" '
function shquote(s) {
gsub(q, q "\" q q, s)
return q s q
}
{
date = $6 " " $7 " " $8
name = $9
cmd = "du -sk " shquote(ENVIRON["DIR"] (ENVIRON["DIR"] ~ /^\/*$/ ? "" : "/") name)
cmd | getline
disk_usage = $1
print date "\t" name "\t" disk_usage
}'
Aqui está uma implementação perl
que não depende da análise da saída de ls -l
(que é inerentemente não confiável) e pode ser facilmente modificada para usar qualquer formato de saída de data ou tamanho necessário .
Salve-o em um arquivo, torne-o executável e execute-o como /path/to/script /usr
. O script requer um ou mais argumentos de nome de diretório.
#!/usr/bin/perl
use strict;
use Date::Format;
if ($#ARGV < 0) { die "Missing directory argument" };
foreach my $dir (@ARGV) {
$dir =~ s:/+$::; # strip trailing /
opendir(my $dh, $dir) || die "Can't opendir $dir: $!";
while (readdir $dh) {
next if (m/^\.{1,2}$/); # skip . and .. entries
my $mtime=(stat("$dir/$_"))[9]; # extract mtime field from stat
my $mtime_f = time2str('%Y-%m-%d %X', $mtime);
open(my $fh, "-|", 'du', '-s', '--', "$dir/$_");
my $du = <$fh>;
($du) = split(' ',$du); # only want the first blank-separated field
close($fh).
printf "%s\t%s\t%s\n", $mtime_f, "$dir/$_" , $du;
}
closedir $dh;
};
Existem maneiras mais simples e curtas de fazer isso (em perl ou awk ou outras linguagens), mas isso fornece uma base útil para relatar outras informações sobre diretórios e seus conteúdos. veja perldoc -f stat
para detalhes completos sobre as informações disponíveis na função stat()
.
BTW, isso pode ser implementado em awk
, mas você precisa implementar sua própria função stat()
e uma função de formatação de data. Mais fácil de usar perl
.
GNU awk
aka gawk
suporta módulos carregáveis e o módulo filefuncs
fornece stat()
que preenche uma matriz statdata[]
. Use adicionando @load "filefuncs"
no topo do seu script awk
.
Tags awk command-substitution