Tutte le possibili combinazioni di caratteri e numeri


13

Quindi voglio generare tutte le possibili combinazioni di caratteri e numeri minuscoli e maiuscoli che possono costituire una stringa di 5 caratteri.

Possibilità: a..z, A..Z e 0..9.

Esiste un modo elegante per farlo in bash?


1
Vuoi limitarti ad ASCII o allo script latino? Che dire dei segni diacritici come gli accenti (é, â ...)?
Stéphane Chazelas,

Grazie per il seguito. Post originale aggiornato per chiarimenti.
Ardevd,

Ha davvero bisogno di essere in bash? Sarà una lingua come Perl o Awk?
terdon

1
Allora perché non chiamare semplicemente Perl o Python da bash? Soprattutto con perl, è molto facile da usare come una fodera.
terdon

2
Stai cercando di imparare o vuoi solo il risultato? Nel secondo caso ci sono molti programmi che fanno il lavoro come john the ripper ( john) e simili, che ti daranno molte possibilità.
YoMismo,

Risposte:


13

Ecco una soluzione bash che accetta la lunghezza desiderata come parametro (come faresti permute 5nel tuo 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, però. Oserei raccomandare 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;
}

Eseguirlo:

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

Le lingue di alto livello fanno schifo alla forza bruta (che è fondamentalmente ciò che stai facendo).


@ Stéphane Chazelas Grazie mille per la modifica. Stavo scrivendo sporco, ignorando la citazione "corretta" in quanto non è necessaria in questo caso, ma sono molto grato per le scorciatoie!
PSkocik,

Ho provato la tua bashsoluzione. È molto carino; Mi piace un sacco. Ha funzionato bene per circa 24 ore prima di notare che il mio sistema era completamente bloccato. Ho provato qualcosa di simile con `python; con un risultato simile, sebbene fosse notevolmente più veloce.
Voci dal

7

In bash, puoi provare:

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

ma ciò richiederebbe un'eternità e consumerebbe tutta la tua memoria. La cosa migliore sarebbe usare un altro strumento come 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"}}}}}'

Attenzione, questo è 6 x 62 5 byte, quindi 5.496.796.992.

Puoi fare lo stesso loop in bash, ma bashessendo la shell più lenta in Occidente, ci vorranno ore:

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

(sul mio sistema, che emette a 700 kiB / s rispetto a 20 MiB / s con l' perlequivalente).


Sento anche che si aggiungerebbe alla risposta se si aggiungesse un modo per inviarlo a un file; forse mentre viene generato in modo da non distruggere la tua RAM, o dopo che è tutto memorizzato nella cache di RAM
Hellreaver,

2
@Hellreaver, scrivono tutti su un file (su stdout, qualunque file sia aperto; se eseguito in un terminale, un file del dispositivo simile /dev/pts/something; e puoi cambiarlo con l'operatore di reindirizzamento della shell), non memoria, ma il primo costruisce l'intero output in memoria prima di inviarlo (al file aperto su stdout).
Stéphane Chazelas,

4

Ecco un modo per farlo puramente in bash senza dover tagliare 5 GB di 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

2

Questa versione bash non è ancora veloce come Perl ma è circa quattro volte più veloce di cinque loop nidificati:

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

Puoi usare crunch(che è disponibile almeno sulle distribuzioni Kali).

crunch 5 5 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890

1

Bene ... elegante ?, sì (solo un campione veloce):

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

Questa espressione completa molto probabilmente bloccherà il tuo computer:

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

Un'opzione non bloccante è utilizzare diversi loop:

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"

Chiamalo come:

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

Dove il primo argomento è il numero di caratteri e il secondo è l'elenco (spazio separato) dei caratteri utilizzati.

Ciò costruirà una variabile ( loop) con lo script da eseguire e l'ultimo eval eseguirà quello script. Ad esempio per:

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

Il valore di loopsarà:

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;

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.