Como obter os resultados do ls canalizado para o wc ao executar dentro de um loop for?

3

Por isso, estou tentando tornar este um único comando em vez de ter que despejar os dados em um arquivo e, em seguida, cat o arquivo e canalizar a saída para wc -l. Toda a linha de código é assim:

for file in 'grep Rawdata freeze2-1.out | awk '{print $6}''
 do
  ls -1 /appdata/frozen_files/$file | wc -l
 done

Mas a saída me dá uma contagem para cada linha, em vez de um total para toda a saída. Existe alguma maneira isso pode ser feito onde eu recebo a saída de um único número para todos os arquivos ou eu tenho que redirecionar para um arquivo e dar mais um passo?

    
por J Telep 17.10.2017 / 04:56

2 respostas

2

Você está tentando contar o número total de arquivos em um diretório nomeado pelo campo 6 no arquivo freeze2-1.out, mas apenas onde "Rawdata" aparece em algum lugar na linha desse arquivo.

O principal erro no seu post inicial foi simplesmente um de lógica ou posicionamento; você estava pedindo a wc -l para contar as linhas individuais dentro do loop dentro de perguntar pelo número total de linhas que o loop geral fornecia. Isso é o que a maioria das respostas existentes está corrigindo.

Eu criei um arquivo de amostra freeze2-1.out para que eu pudesse "tocar junto em casa"; aqui está o que eu coloco:

Rawdata 2 3 4 5 file1
Rawdata 2 3 4 5 file2
Rawdata 2 3 4 5 file3

Eu também preenchei um diretório relativo chamado "appdata / frozen_files" com nomes de diretório baseados no campo 6 acima. Observe que seu caminho real é um caminho absoluto começando com / appdata / frozen_files. Coloquei 1 arquivo no arquivo1, 2 no arquivo2 e 3 no arquivo3, para um total de 6 arquivos.

O primeiro aprimoramento que sugiro é combinar o grep e o awk , já que o awk pode fazer a correspondência de padrões. RomanPerekhrest também fez isso em sua resposta:

awk '/Rawdata/ { print $6 }' freeze2-1.out

A saída da amostra é então:

file1
file2
file3

Vou apontar aqui que, como o awk divide os campos com base em espaços, tabulações e novas linhas, imprimir especificamente no campo 6 implica que cada linha de saída terá uma palavra sem espaços.

Existem algumas maneiras de contar o número de arquivos em um diretório. Usar ls -1 | wc -l é um caminho, mas falha em um caso muito particular em que um nome de arquivo possui uma nova linha incorporada; você poderia criar tal arquivo manualmente com touch $'file\nname' . Como o awk está lendo linhas de entrada delimitadas por novas linhas, não vamos encontrar esse caso especial aqui, mas eu queria mencioná-lo. Por exemplo:

# create the file
$ touch $'file\nname'

# check the listing; looks okay so far
$ ls -1
appdata
file?name
freeze2-1.out

# count them up
$ ls -1 | wc -l
4 

# woops! should be 3!

Por esse motivo, demonstrarei dois outros métodos para contar os arquivos em um diretório.

O primeiro método usa o set embutido para pegar seus argumentos e convertê-los em argumentos posicionais nomeados por $ 1, $ 2, $ 3, etc.

$ sum=0
$ for file in $(awk '/Rawdata/ { print $6 }' freeze2-1.out)
  do
    set -- "appdata/frozen_files/${file}/"*
    sum=$((sum + $#))
  done
$ echo "$sum"
6

Isso inicializa um contador sum para zero e, em seguida, percorre os nomes dos arquivos da saída awk. Ele chama set com o caminho entre aspas para o diretório, seguido pelo * shell glob, que é expandido para todos os arquivos (não ocultos) desse diretório. Isso corresponde ao comportamento ls -1 de excluir arquivos ocultos (aqueles que começam com um ponto). O número de parâmetros é dado pela variável especial $# , que adicionamos dentro do loop a sum , depois imprimimos no final.

Um segundo método, para shells que suportam arrays, é colocar os nomes de arquivos em globalização em uma matriz e, em seguida, contar os elementos da matriz:

$ sum=0
$ for file in $(awk '/Rawdata/ { print $6 }' freeze2-1.out )
  do
    n=("appdata/frozen_files/${file}"/*)
    sum=$((sum + ${#n[@]}))
  done
$ echo "$sum"
6
    
por 17.10.2017 / 18:14
0

Mova a contagem de palavras para o final;

for file in $(grep Rawdata freeze2-1.out | awk '{print $6}')
 do
  ls -1 /appdata/frozen_files/$file
 done | wc -l

ou some-a;

C=0
for file in $(grep Rawdata freeze2-1.out | awk '{print $6}')
 do
  C=$[$C+$(ls -1 /appdata/frozen_files/$file | wc -l)]
 done
echo $C;

ou talvez use find se sua estrutura de arquivos puder corresponder a um padrão (ou regex)

find /appdata/frozen_files/ -iname '*.raw' |wc -l
    
por 17.10.2017 / 05:01

Tags