Toutes les combinaisons possibles de caractères et de chiffres

13

Je veux donc générer toutes les combinaisons possibles de caractères minuscules et majuscules et de nombres pouvant constituer une chaîne de 5 caractères.

Possibilités: a..z, A..Z et 0..9.

Existe-t-il une manière élégante de le faire en bash?

ardevd
la source
1
Voulez-vous vous limiter à l'ASCII ou au script latin? Et les diacritiques comme les accents (é, â ...)?
Stéphane Chazelas
Merci pour le suivi. Mise à jour du message d'origine pour clarification.
ardevd
Est - il vraiment besoin d'être en bash? Est-ce qu'une langue comme Perl ou awk fera l'affaire?
terdon
1
Alors pourquoi ne pas simplement appeler Perl ou Python depuis bash? Surtout avec perl, il est très facile de l'utiliser comme une doublure.
terdon
2
Essayez-vous d'apprendre ou voulez-vous simplement le résultat? Dans le second cas, il existe de nombreux programmes qui font le travail comme John the Ripper ( john) et autres, ce qui vous offrira de nombreuses possibilités.
YoMismo

Réponses:

13

Voici une solution bash qui prend la longueur souhaitée comme paramètre (vous feriez permute 5dans votre cas):

#!/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"

C'est douloureusement lent, cependant. Oserais-je recommander 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;
}

Exécuter:

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

Les langages de haut niveau aspirent au forçage brutal (ce qui est essentiellement ce que vous faites).

PSkocik
la source
@ Stéphane Chazelas Merci beaucoup pour cette retouche. J'écrivais sale, ignorant les citations "correctes" car ce n'est pas nécessaire dans ce cas, mais je suis très reconnaissant pour les raccourcis!
PSkocik
J'ai essayé ta bashsolution. C'est très gentil; Je l'aime beaucoup. Cela a bien fonctionné pendant environ 24 heures avant de remarquer que mon système était complètement verrouillé. J'ai essayé quelque chose de similaire avec `python; avec un résultat similaire, bien que ce fut beaucoup plus rapide.
voix
7

Dans bash, vous pouvez essayer:

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

mais cela prendrait une éternité et épuiserait toute votre mémoire. Le mieux serait d'utiliser un autre outil comme 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"}}}}}'

Attention c'est 6 x 62 5 octets donc 5 496 796 992.

Vous pouvez faire la même boucle bash, mais bashétant l'obus le plus lent de l'ouest, cela va prendre des heures:

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

(sur mon système, qui sort à 700 kio / s contre 20 Mo / s avec l' perléquivalent).

Stéphane Chazelas
la source
Je pense également que cela ajouterait à la réponse si vous deviez ajouter un moyen de le produire dans un fichier; peut-être au fur et à mesure qu'il est généré pour ne pas détruire votre RAM, ou après que tout est mis en cache dans le ram
Hellreaver
2
@Hellreaver, ils écrivent tous dans un fichier (vers stdout, quel que soit le fichier ouvert; s'il est exécuté dans un terminal, un fichier de périphérique comme /dev/pts/something; et vous pouvez le changer avec l'opérateur de redirection shell), pas de mémoire, mais le premier construit toute la sortie en mémoire avant de la sortir (vers le fichier ouvert sur stdout).
Stéphane Chazelas
4

Voici un moyen de le faire uniquement en bash sans avoir à réduire 5 Go de mémoire:

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 dit «Réintègre Monica»
la source
2

Cette version bash n'est toujours pas aussi rapide que Perl mais elle est environ quatre fois plus rapide que cinq boucles imbriquées:

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
la source
1

Vous pouvez utiliser crunch(qui est disponible au moins sur les distributions Kali).

crunch 5 5 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890
user123456
la source
1

Eh bien ... élégant ?, oui (juste un échantillon rapide):

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

Cette expression complète bloquera probablement votre ordinateur:

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

Une option non bloquante consiste à utiliser plusieurs boucles:

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"

Appelez ça comme:

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

Où le premier argument est le nombre de caractères et le second est la liste (séparée par des espaces) des caractères utilisés.

Cela va construire une variable ( loop) avec le script à exécuter et le dernier eval exécutera ce script. Par exemple pour:

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

La valeur de loopsera:

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
la source
1

Gnu Parallel peut faire des combinaisons voir https://www.gnu.org/software/parallel/ Quelque chose comme ceci:

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
la source