Iterando por pastas em ordem numérica

2

Eu tenho um monte de pastas que são rotuladas desta forma:

 conf1
 conf2
 ...

Mas a ordem no diretório inicial é como

 conf1
 conf10
 conf100
 conf101
 ...
 conf2
 conf20
 conf200
 conf201
 ...

Como cada pasta contém um arquivo chamado "distance.txt", eu gostaria de poder imprimir o conteúdo do arquivo distance.txt, de cada pasta, mas na ordem, indo da pasta 1 - > 2 - > 3 ... para a pasta final 272.

Eu tentei várias tentativas, mas toda vez que o arquivo final contém todo o conjunto de valores na ordem errada; essa é a parte do código que eu configurei:

   ls -v | for d in ./*/; 
     do (cd "$d" && cat distance.txt >> /path/to/folder/d.txt
         );
     done

Como você pode ver, tentei "ordenar" as pastas com o comando

ls -v

e, em seguida, acoplar o ciclo para salvar iterativamente cada arquivo.

Você pode gentilmente me ajudar?

    
por Tommaso Francese 12.03.2017 / 17:36

6 respostas

5

Para um conjunto relativamente pequeno de pastas, você pode usar um loop numérico

for n in {1..272}
do
    d="conf$n"
    test-d "$d" && cat "$d/distance.txt" >> /path/to/folder/d.txt
done
    
por 12.03.2017 / 18:01
3

Se você tem um sort que suporta delimitadores nulos e classificação de versões, você pode fazer com segurança

printf '%s
for d in conf*(/n); do
  whatever with "$d"
done
' conf*/ | sort -zV | while read -rd '' d; do whatever with "$d" done

eu acho. Se você tem zsh é muito mais fácil, pois suporta um qualificador de glob numérico

printf '%s
for d in conf*(/n); do
  whatever with "$d"
done
' conf*/ | sort -zV | while read -rd '' d; do whatever with "$d" done
    
por 12.03.2017 / 18:09
0
printf '%s\n' conf{1..101} conf{2..272} |
xargs sh -c 'shift "$1"; printf "%s/distance.txt\n" "$@"' 2 1 > /path/to/folder.txt

Ou

printf '%s\n' conf{1..101}/distance.txt conf{2..272}/distance.txt |
xargs cat > /path/to/folder.txt
    
por 12.03.2017 / 18:00
0
printf 'conf%s/distance.txt\n' {1..272} | xargs cat >/path/to/folder/d.txt 2>/dev/null

Aqui fazemos uso do fato de que se o dir. confNNN/ & / ou distance.txt não existem, será gerado um aviso que ignoramos. A saída real acontece apenas no caso do arquivo dir + existir, portanto, não há necessidade de testar o arquivo & dir. existência. cat para o resgate.

Além disso, não há necessidade de >> de acréscimo, como xargs , mesmo que invoque cat várias vezes, e ainda despeja a saída em um grupo no log.

Então, é um lugar que não é um UUOC ; -)

    
por 12.03.2017 / 18:26
0

Crie um minúsculo perlscript para ordenar os argumentos passados pelo shell:

#!/usr/bin/perl -l -s

$re ||= qr/(\d+)/;

sub bynum {
   ($aa) = $a =~ $re;
   ($bb) = $b =~ $re;
   return $aa <=> $bb;
}

map { print } sort bynum @ARGV;

Salve o script como sortargsbynum e chame-o como expressão de shell:

for d in $(sortargsbynum conf*); do
   cat $d/distance.txt >> /path/to/folder/d.txt
done

Você pode transmitir uma expressão regular especial para correspondência, por exemplo, para corresponder apenas a um número no final do nome:

for d in $(sortargsbynum -re='(\d+)$' *conf*); do
   echo $d
done

conf1
conf2
conf10
conf20
conf99
1stconf100
2ndconf100
conf101
conf200
conf201
    
por 12.03.2017 / 18:50
0

Você pode classificar primeiro pelo comprimento da string e depois lexicograficamente se tudo compartilhar um prefixo comum. Se dois números tiverem o mesmo número de dígitos, a comparação lexicográfica e numérica resultará na mesma ordem.

 ls -1 | awk '{print $1 " " length($1)}' | sort -n -k2,2 -k1,1 | awk '{print $1}'

Você também pode usar perl para coletar os nomes das pastas e extrair o sufixo numérico à direita. Então você pode ordenar numericamente com base neste sufixo.

ls -1 | perl -e '@lines = <STDIN>; @lines = sort { $a =~ /(\d+)$/; $aa = $1; $b =~ /(\d+)$/; $aa <=> $1;  } @lines; print foreach @lines;'
    
por 12.03.2017 / 18:49