Bash divide uma lista de arquivos

5

Eu tenho 200 arquivos em uma pasta como: test_1_cfg.dat , test_2_cfg.dat , .... e assim por diante. Eu preciso incluir em um script bash os primeiros 40 arquivos como entrada e executar algum processo, outro script para ler os próximos 40 arquivos e executar outro processo.

Então eu estava pensando em uma maneira de ter uma lista dos nomes dos arquivos e depois apenas dividir essa lista, mas não sei como fazer isso no bash.

Alguma ideia?

    
por Alejandro 01.04.2014 / 04:49

3 respostas

9

Método # 1 - Usando head & cauda

Você pode usar o comando head para extrair os primeiros 40 arquivos de uma listagem de arquivos da seguinte forma:

$ head -40 input_files | xargs ...

Para obter os próximos 40:

$ tail -n +41 input_file  | head -40 | xargs ...

...

$ tail -n +161 input_file | head -40 | xargs ...

Você pode continuar andando na lista, 40 de cada vez usando essa mesma técnica.

Método # 2 - Usando xargs

Se você tiver todos os seus nomes de arquivos em uma variável, você pode usar xargs da mesma forma para dividir a lista em partes do número X de elementos.

Exemplo

Finja que meus arquivos são chamados de 1-200. Então eu os carrego em uma variável assim:

$ files=$(seq 200)

Você pode ver o primeiro par de itens nessa variável:

$ echo $files  | head -c 20
1 2 3 4 5 6 7 8 9 10

Agora usamos xargs para dividir:

$ xargs -n 40 <<<$files
1 2 3 4 5 6 7 8 9 10 ...
41 42 43 44 45 46 47 ...
81 82 83 84 85 86 87 ...
121 122 123 124 125 ...
141 142 143 144 145 ...
161 162 163 164 165 ...
181 182 183 184 185 ...

Você poderia então passar o comando acima para outro xargs , que então executaria seu programa:

$ xargs -n 40 <<<$files | xargs ...

Se o conteúdo da lista de arquivos não for facilmente acessível a partir de uma variável, você poderá fornecer xargs uma lista por meio de um arquivo:

$ xargs -n 40 <input_file
1 2 3 4 5 6 7 8 9 10 ...
41 42 43 44 45 46 47 ...
81 82 83 84 85 86 87 ...
121 122 123 124 125 ...
141 142 143 144 145 ...
161 162 163 164 165 ...
181 182 183 184 185 ...

Método # 3 - Matrizes Bash

Digamos que você tenha seus nomes de arquivos em uma matriz Bash. Novamente, estou usando uma sequência do número 1-200 para representar meus nomes de arquivos.

$ foo=( $(seq 200) )

Você pode ver o conteúdo da matriz assim:

$ echo ${foo[@]}
1 2 3 4 5 ....

Agora, para obter o primeiro 40:

$ echo "${foo[@]:0:40}"

O segundo 40, etc:

$ echo "${foo[@]:40:40}"
...
$ echo "${foo[@]:160:40}"
    
por 01.04.2014 / 05:02
7

Esta é uma receita perfeita para xargs :

cat list_of_files | xargs -n 40 command

Citações de man xargs :

 -n number   Set the maximum number of arguments taken from standard input
             for each invocation of the utility.  An invocation of utility
             will use less than number standard input arguments if the
             number of bytes accumulated (see the -s option) exceeds the
             specified size or there are fewer than number arguments
             remaining for the last invocation of utility.  The current
             default value for number is 5000.

Para realizar ações diferentes para cada conjunto, você precisa obter linhas relevantes antes de passá-las para xargs :

 sed -n '1,40p' list_of_files | xargs command1
 sed -n '41,80p' list_of_files | xargs command2
 ...     
    
por 01.04.2014 / 04:52
0

FYI, ADORO o xargs -n 40 <<<$files mas como ele faz "40 args" por linha que eu fiz

threads=10
xargs -n $((40/threads)) <<<$files

ou se estiver em uma matriz ..

n=(1 2 3 4 5 6)
xargs -n $((${#n[@]}/threads))

while read -r input; do
  for item in $input; do
    <..stuff..>
  done &
done <<< $(for x in ${n[@]}; do echo $x; done | xargs -n $((${#n[@]}/threads)))
wait
    
por 09.11.2017 / 20:55