Alle möglichen Kombinationen von Zeichen und Zahlen

13

Ich möchte also alle möglichen Kombinationen von Klein- und Großbuchstaben und Zahlen generieren, die eine 5-stellige Zeichenfolge bilden können.

Möglichkeiten: a..z, A..Z und 0..9.

Gibt es eine elegante Möglichkeit, dies in Bash zu tun?

Ardevd
quelle
1
Möchten Sie sich auf ASCII oder die lateinische Schrift beschränken? Was ist mit Diakritika wie Akzenten (é, ...)?
Stéphane Chazelas
Vielen Dank für das Follow-up. Aktualisierter Originalbeitrag zur Klarstellung.
Freitag,
Ist es wirklich braucht in bash zu sein? Kann eine Sprache wie Perl oder awk?
terdon
1
Dann rufen Sie doch einfach Perl oder Python aus der Bash heraus an. Besonders bei perlist es sehr einfach, es als Einzeiler zu verwenden.
terdon
2
Versuchen Sie zu lernen oder wollen Sie nur das Ergebnis? Im zweiten Fall gibt es viele Programme, die die Arbeit erledigen, wie John the Ripper ( john) und dergleichen, die Ihnen viele Möglichkeiten bieten.
YoMismo

Antworten:

13

Hier ist eine Bash-Lösung, die die gewünschte Länge als Parameter verwendet (was Sie permute 5in Ihrem Fall tun würden):

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

Es ist allerdings schmerzhaft langsam. Kann ich C empfehlen? 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;
}

Starte es:

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

Hochrangige Sprachen lügen am brachialen Treiben (was im Grunde das ist, was Sie tun).

PSkocik
quelle
@Stéphane Chazelas Vielen Dank für die Bearbeitung. Ich habe schmutzig geschrieben und "richtige" Zitate ignoriert, da sie in diesem Fall nicht benötigt werden, aber ich bin sehr dankbar für die Abkürzungen!
PSkocik
Ich habe deine bashLösung ausprobiert . Es ist sehr nett; Ich mag es sehr. Es hat ungefähr 24 Stunden lang gut funktioniert, bevor ich bemerkte, dass mein System vollständig gesperrt war. Versuchte etwas Ähnliches mit `Python; mit einem ähnlichen Ergebnis, obwohl es wesentlich schneller war.
Stimmen
7

In bashkönnten Sie versuchen:

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

aber das würde ewig dauern und all dein Gedächtnis verbrauchen. Am besten verwenden Sie ein anderes Tool wie 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"}}}}}'

Achtung, das sind 6 x 62 5 Bytes, also 5.496.796.992.

Sie können die gleiche Schleife in machen bash, aber bashals langsamste Muschel im Westen wird das Stunden dauern:

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

(Auf meinem System werden 700 kB / s ausgegeben, im Gegensatz zu 20 MB / s mit dem perlÄquivalent).

Stéphane Chazelas
quelle
Ich bin auch der Meinung, dass es die Antwort ergänzen würde, wenn Sie eine Möglichkeit hinzufügen würden, sie in eine Datei auszugeben. Vielleicht, weil es generiert wird, um Ihren RAM nicht zu zerstören, oder nachdem alles im RAM zwischengespeichert wurde
Hellreaver
2
@Hellreaver, sie alle schreiben in eine Datei (nach stdout, welche Datei auch immer geöffnet ist; wenn sie in einem Terminal ausgeführt wird, wie eine Gerätedatei /dev/pts/something; und Sie können dies mit dem Shell-Umleitungsoperator ändern), nicht in den Speicher, sondern in die erste, die erstellt wird die gesamte Ausgabe im Speicher, bevor sie ausgegeben wird (in die auf stdout geöffnete Datei).
Stéphane Chazelas
4

Hier ist eine Möglichkeit, dies in bash zu tun, ohne 5 GB Arbeitsspeicher benötigen zu müssen:

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 sagt, "Monica wiedereinstellen"
quelle
2

Diese Bash-Version ist immer noch nicht so schnell wie Perl, aber ungefähr viermal so schnell wie fünf verschachtelte Schleifen:

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
quelle
1

Sie können verwenden crunch(was zumindest auf Kali-Distributionen verfügbar ist).

crunch 5 5 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890
user123456
quelle
1

Naja ... elegant ?, ja (nur eine schnelle Probe):

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

Dieser vollständige Ausdruck blockiert höchstwahrscheinlich Ihren Computer:

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

Eine nicht blockierende Option besteht darin, mehrere Schleifen zu verwenden:

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"

Nennen Sie es wie folgt:

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

Dabei ist das erste Argument die Anzahl der Zeichen und das zweite die durch Leerzeichen getrennte Liste der verwendeten Zeichen.

Dadurch wird eine Variable ( loop) mit dem auszuführenden Skript erstellt, und die letzte Auswertung führt dieses Skript aus. Zum Beispiel für:

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

Der Wert von loopwird sein:

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;
Isaac
quelle
1

Gnu Parallel tun können , siehe Kombinationen https://www.gnu.org/software/parallel/ Etwas wie folgt aus :

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
quelle