executa comandos dentro do awk antes da impressão

1

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.

    
por chistof 02.08.2017 / 07:28

3 respostas

1

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.

    
por 02.08.2017 / 10:24
1

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
  }'
    
por 02.08.2017 / 09:13
0

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 .

    
por 02.08.2017 / 08:29