executa o comando em um intervalo definido de diretórios

5

É possível "particionar" uma listagem de diretórios - digamos, em blocos de alguns números, para executar ações diferentes em cada 'intervalo'?

Por exemplo, digamos que eu tenha os seguintes diretórios dentro de outra pasta:

$ ls test
abc/
def/
hij/
klm/
nop/
qrs/
tuv/
wxy/
zzz/

E eu quero realizar alguma ação nos três primeiros diretórios, outro no segundo e assim por diante.

Meu pensamento era que talvez um loop entre os números funcionaria, baseado na saída de algo como ls | nl (mas antes que alguém o mencione, eu sei que analisar ls é um não-não!)

Isso obviamente não funciona, mas ilustra meu ponto de vista:

for dir in 'ls | nl'; 
do
    do-something-with ${dir{1..3}} # Where $dir has taken on some numerical value linked to the folder)
    do-something-with ${dir{4..6}} 
# And so on...
    do-something-with ${dir{n-3..n}} 
done

As pastas nas quais pretendo realmente fazer isso podem ser trabalhadas em qualquer ordem (isto é, as divisões finais podem ser totalmente arbitrárias), mas elas não têm consistência de nomenclatura lógica - com isso quero dizer que não podem ser organizadas de maneira sensata alfabética ou numericamente com base em qualquer chave dentro do próprio nome do diretório.

    
por Joe Healey 13.04.2016 / 11:31

5 respostas

3

Não há motivos para fazer um dos erros abaixo para esta situação:

  1. Use extensões GNU não portáteis (como xargs -0 )
  2. Analise os nomes de arquivos apenas como um fluxo de texto, fingindo que eles não podem conter novas linhas.

Você pode lidar com isso de maneira portável sem muita dificuldade:

set -- */
while [ "$#" -gt 0 ]; do
  case "$#" in
    1)
      my-command "$1"
      shift 1
      ;;
    2)
      my-command "$1" "$2"
      shift 2
      ;;
    *)
      my-command "$1" "$2" "$3"
      shift 3
      ;;
  esac
done

Realmente isso é mais detalhado do que o necessário, mas é legível dessa maneira.

Para um tipo diferente de particionamento, onde você quer dividir todos os diretórios em exatamente três diferentes métodos de manuseio (mas não precisa lidar com eles ao mesmo tempo), você pode fazer da seguinte forma:

x=1
for d in *; do
  [ ! -d "$d" ] && continue
  case "$x" in
    1)
      # do stuff with "$d"
      ;;
    2)
      # do stuff with "$d"
      ;;
    3)
      # do stuff with "$d"
      ;;
  esac
  x=$(($x+1))
  [ "$x" -eq 4 ] && x=1
done
    
por 15.04.2016 / 03:46
3

com printf/xargs :

printf "%s
do-something abc/ def/ hij/
do-something klm/ nop/ qrs/
do-something tuv/ wxy/ zzz/
" */ | xargs -0 -n3 echo do-something
  • printf imprime o conteúdo do diretório atual com delimitação nula. A barra após o * corresponde somente aos diretórios, não aos arquivos.
  • xargs lê a entrada nula delimitada -0
    • -n3 divide a entrada em 3 partes.

A saída (com seus diretórios de exemplo):

printf "%s
do-something abc/ def/ hij/
do-something klm/ nop/ qrs/
do-something tuv/ wxy/ zzz/
" */ | xargs -0 -n3 echo do-something
    
por 13.04.2016 / 11:50
0

O argumento -n para xargs pode às vezes ser usado para isso. Se você deseja executar tarefas em paralelo, a opção -P também pode ser usada.

/tmp/t$ ls -1
dir1
dir2
dir3
dir4

/tmp/t$ ls -1 |xargs -n 3 echo runcmd
runcmd dir1 dir2 dir3
runcmd dir4

Não se preocupe muito em analisar a saída de ls|nl . Se você precisa se preocupar com esse tipo de coisa, você pode usar find .. -print0 e o argumento -0 para xargs. (assumindo que ambos estão disponíveis).

    
por 13.04.2016 / 11:41
0

Se eu pudesse modificar a resposta de Otheus, seria assim

for d in ''ls -1 | xargs -n 3 echo' ; do (cd "$d" && somecommand); done
e assim por diante com outros diretórios também.     
por 13.04.2016 / 11:55
0

Como a solução do Wildcard é a que eu usei, eu marquei a resposta dele como aceita, mas se for útil para pessoas tropeçarem no futuro, abaixo está o meu código para distribuir 330 diretórios entre 11 outros diretórios igualmente. / p>

Talvez valha a pena assinalar que também parecia muito rápido!

#!/bin/bash

numdirs=11

for ((i=1; i<=$numdirs; i++))
do
    mkdir -p ~/simulation_groups/group_${i}
done

x=1

for d in * ; do
  [ ! -d "$d" ] && continue
  case "$x" in
1)
  mv $d ~/simulation_groups/group_${x}
  ;;
2)
  mv $d ~/simulation_groups/group_${x}
  ;;
3)
  mv $d ~/simulation_groups/group_${x}
  ;;
4)
  mv $d ~/simulation_groups/group_${x}
  ;;
5)
  mv $d ~/simulation_groups/group_${x}
  ;;
6)
  mv $d ~/simulation_groups/group_${x}
  ;;
7)
  mv $d ~/simulation_groups/group_${x}
  ;;
8)
  mv $d ~/simulation_groups/group_${x}
  ;;
9)
  mv $d ~/simulation_groups/group_${x}
  ;;
10)
  mv $d ~/simulation_groups/group_${x}
  ;;
11)
  mv $d ~/simulation_groups/group_${x}
  ;;
  esac
  x=$(($x+1))
  [ "$x" -eq $numdirs+1 ] && x=1
done
    
por 18.04.2016 / 12:01