Todas las combinaciones posibles de caracteres y números.

13

Por lo tanto, quiero generar todas las combinaciones posibles de caracteres y números en mayúsculas y minúsculas que pueden formar una cadena de 5 caracteres.

Posibilidades: a..z, A..Z y 0..9.

¿Hay alguna forma elegante de hacer esto en bash?

Ardevd
fuente
1
¿Quieres limitarte a ASCII o al script latino? ¿Qué pasa con los signos diacríticos como los acentos (é, â ...)?
Stéphane Chazelas
Gracias por el seguimiento. Publicación original actualizada para aclaraciones.
ardevd
¿Realmente necesita estar en bash? ¿Lo hará un lenguaje como Perl o awk?
terdon
1
Entonces, ¿por qué no simplemente llamar a Perl o Python desde bash? Especialmente con perl, es muy fácil usarlo como una sola línea.
terdon
2
¿Estás tratando de aprender o solo quieres el resultado? En el segundo caso, hay muchos programas que hacen el trabajo como John the Ripper ( john) y similares, lo que le dará muchas posibilidades.
YoMismo

Respuestas:

13

Aquí hay una solución bash que toma la longitud deseada como parámetro (lo haría permute 5en su 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"

Sin embargo, es dolorosamente lento. ¿Me atrevo a 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;
}

Ejecutarlo:

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

Los lenguajes de alto nivel apestan en la fuerza bruta (que es básicamente lo que estás haciendo).

PSkocik
fuente
@ Stéphane Chazelas Muchas gracias por esa edición. Estaba escribiendo sucio, ignorando las citas "adecuadas", ya que no es necesario en este caso, ¡pero estoy muy agradecido por los atajos!
PSkocik
Probé tu bashsolución. Es muy bonito; Me gusta mucho. Funcionó bien durante aproximadamente 24 horas más o menos antes de notar que mi sistema estaba completamente bloqueado. Intenté algo similar con `python; con un resultado similar, aunque fue considerablemente más rápido.
voces
7

En bash, puedes probar:

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}}

pero eso llevaría una eternidad y agotaría toda tu memoria. Lo mejor sería usar otra herramienta 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, eso es 6 x 62 5 bytes, entonces 5,496,796,992.

Puedes hacer el mismo bucle bash, pero al bashser el caparazón más lento del oeste, tomará 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

(en mi sistema, eso genera 700 kiB / s en lugar de 20MiB / s con el perlequivalente).

Stéphane Chazelas
fuente
También siento que se agregaría a la respuesta si tuviera que agregar una forma de enviarlo a un archivo; tal vez como se está generando para que no destruya su RAM, o después de que todo esté en caché en ram
Hellreaver
2
@Hellreaver, todos escriben en un archivo (en stdout, cualquier archivo que esté abierto; si se ejecuta en un terminal, un archivo de dispositivo como /dev/pts/something; y puede cambiar eso con el operador de redirección de shell), no memoria, pero el primero se construye toda la salida en la memoria antes de enviarla (al archivo abierto en stdout).
Stéphane Chazelas
4

Aquí hay una manera de hacerlo únicamente en bash sin tener que consumir 5 GB de memoria:

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
G-Man dice 'restablecer a Mónica'
fuente
2

Esta versión bash todavía no es tan rápida como Perl, pero es aproximadamente cuatro veces más rápida que cinco bucles anidados:

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
rici
fuente
1

Puede usar crunch(que está disponible al menos en las distribuciones de Kali).

crunch 5 5 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890
usuario123456
fuente
1

Bueno ... ¿elegante ?, sí (solo una muestra rápida):

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

Esta expresión completa probablemente bloqueará su computadora:

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

Una opción sin bloqueo es usar varios bucles:

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"

Llámalo como:

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

Donde el primer argumento es el número de caracteres y el segundo es la lista (separada por espacios) de los caracteres utilizados.

Eso generará una variable ( loop) con el script que se ejecutará y la última evaluación ejecutará ese script. Por ejemplo para:

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

El 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;
NotAnUnixNazi
fuente
1

Gnu Parallel puede hacer combinaciones, consulte https://www.gnu.org/software/parallel/ Algo como esto:

parallel echo ::: {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}
Christopher Barham
fuente