Todas as combinações possíveis de caracteres e números


13

Então, eu quero gerar todas as combinações possíveis de caracteres e números em maiúsculas e minúsculas que podem formar uma sequência de 5 caracteres.

Possibilidades: a..z, A..Z e 0..9.

Existe alguma maneira elegante de fazer isso no bash?


1
Deseja limitar-se ao ASCII ou ao script latino? E os diacríticos como sotaques (é, â ...)?
Stéphane Chazelas

Obrigado pelo seguimento. Post original atualizado para esclarecimentos.
Ardevd 18/05/19

Realmente precisa estar no bash? Será que um idioma como Perl ou awk funciona?
terdon

1
Então, por que não chamar Perl ou Python do bash? Especialmente com perl, é muito fácil usá-lo como uma linha.
terdon

2
Você está tentando aprender ou apenas quer o resultado? No segundo caso, existem muitos programas que fazem o trabalho como john the ripper ( john) e similares, o que lhe dará muitas possibilidades.
YoMismo

Respostas:


13

Aqui está uma solução bash que leva o comprimento desejado como parâmetro (você faria permute 5no seu caso):

#!/bin/bash
charset=({a..z} {A..Z} {0..9})
permute(){
  (($1 == 0)) && { echo "$2"; return; }
  for char in "${charset[@]}"
  do
    permute "$((${1} - 1 ))" "$2$char"
  done
}
permute "$1"

É dolorosamente lento, no entanto. Ouso recomendar C? https://youtu.be/H4YRPdRXKFs?t=18s

#include <stdio.h>

//global variables and magic numbers are the basis of good programming
const char* charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
char buffer[50];

void permute(int level) {
  const char* charset_ptr = charset;
  if(level == -1){
    puts(buffer);
  }else {
   while(buffer[level]=*charset_ptr++) {
    permute(level - 1);
   }
  }
}

int main(int argc, char **argv)
{

  int length;
  sscanf(argv[1], "%d", &length); 

  //Must provide length (integer < sizeof(buffer)==50) as first arg;
  //It will crash and burn otherwise  

  buffer[length]='\0';
  permute(length - 1);
  return 0;
}

Executá-lo:

make CFLAGS=-O3 permute && time ./permute 5 >/dev/null #about 20s on my PC

Os idiomas de alto nível são péssimos com força bruta (que é basicamente o que você está fazendo).


@ Stéphane Chazelas Muito obrigado por essa edição. Eu estava escrevendo sujo, ignorando as citações "apropriadas", pois não são necessárias neste caso, mas sou muito grato pelos atalhos!
PSKocik 18/05

Eu tentei sua bashsolução. É muito bom; Eu gosto muito. Funcionou bem por cerca de 24 horas antes de eu perceber que meu sistema estava completamente bloqueado. Tentei algo semelhante com o `python; com um resultado semelhante, embora tenha sido consideravelmente mais rápido.
vozes

7

Em bash, você pode tentar:

printf "%s\n" {{a..z},{A..Z},{0..9}}{{a..z},{A..Z},{0..9}}{{a..z},{A..Z},{0..9}}{{a..z},{A..Z},{0..9}}{{a..z},{A..Z},{0..9}}

mas isso levaria uma eternidade e gastaria toda a sua memória. O melhor seria usar outra ferramenta como perl:

perl -le '@c = ("A".."Z","a".."z",0..9);
          for $a (@c){for $b(@c){for $c(@c){for $d(@c){for $e(@c){
            print "$a$b$c$d$e"}}}}}'

Cuidado com 6 x 62 5 bytes, portanto, 5.496.796.992.

Você pode fazer o mesmo loop bash, mas, bashsendo o shell mais lento do oeste, isso levará horas:

export LC_ALL=C # seems to improve performance by about 10%
shopt -s xpg_echo # 2% gain (against my expectations)
set {a..z} {A..Z} {0..9}
for a do for b do for c do for d do for e do
  echo "$a$b$c$d$e"
done; done; done; done; done

(no meu sistema, isso gera 700 kiB / s em oposição a 20MiB / s com o perlequivalente).


Eu também acho que isso adicionaria à resposta se você adicionasse uma maneira de produzi-la em um arquivo; talvez como está sendo gerado para que ele não destruir a sua RAM, ou depois está tudo em cache na RAM
Hellreaver

2
@Hellreaver, todos eles gravam em um arquivo (no stdout, qualquer arquivo que esteja aberto; se executado em um terminal, um arquivo de dispositivo como /dev/pts/something; e você pode alterar isso com o operador de redirecionamento de shell), não na memória, mas o primeiro cria toda a saída na memória antes de enviá-la (para o arquivo aberto no stdout).
Stéphane Chazelas

4

Aqui está uma maneira de fazê-lo puramente no bash sem ter que consumir 5 GB de memória:

for c1 in {A..Z} {a..z} {0..9}
do
    for c2 in {A..Z} {a..z} {0..9}
    do
        for c3 in {A..Z} {a..z} {0..9}
        do
            for c4 in {A..Z} {a..z} {0..9}
            do
                for c5 in {A..Z} {a..z} {0..9}
                do
                    printf "%s\n" "$c1$c2$c3$c4$c5"
                done
            done
        done
    done
done

2

Essa versão do bash ainda não é tão rápida quanto o Perl, mas é cerca de quatro vezes mais rápida que cinco loops aninhados:

printf -vtwo "%s " {{a..z},{A..Z},{0..9}}{{a..z},{A..Z},{0..9}}
for three in {{a..z},{A..Z},{0..9}}{{a..z},{A..Z},{0..9}}{{a..z},{A..Z},{0..9}}; do
    printf "$three%s\n" $two;
done

1

Você pode usar crunch(disponível pelo menos nas distribuições Kali).

crunch 5 5 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890

1

Bem ... elegante ?, sim (apenas uma amostra rápida):

eval echo $(printf "%s" '{{a..z},{A..Z},{0..9}}'{,,} )

Essa expressão completa provavelmente irá bloquear o seu computador:

eval echo $(printf "%s" '{{a..z},{A..Z},{0..9}}'{,,,,} )

Uma opção sem bloqueio é usar vários loops:

nl=$'\n'; tab=$'\t'
n=${1:-3}
eval set -- "$2"

eval "varnames=($(echo {a..z}))"

for i in "${varnames[@]:0:$n}"; do
    header+='for '"$i"' do '
    middle+='$'"$i"
    traile+="done; "
done

loop="${header}${nl}    printf %s \"$middle\";${nl}$traile"
#echo "$loop"
eval "$loop"

Chame assim:

./script 3 '{a..z} {A..Z} {0..9}'

Onde o primeiro argumento é o número de caracteres e o segundo é a lista (separada por espaço) dos caracteres usados.

Isso criará uma variável ( loop) com o script a ser executado e o último avaliação executará esse script. Por exemplo para:

$ ./script 5 '{a..z} {A..Z} {0..9}'

O valor de loopserá:

for a do for b do for c do for d do for e do
    echo "$a$b$c$d$e";
done; done; done; done; done;

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.