Semua kemungkinan kombinasi karakter dan angka


13

Jadi saya ingin melakukan semua kemungkinan kombinasi karakter huruf kecil dan huruf besar dan angka yang dapat membentuk string 5 karakter.

Kemungkinan: a..z, A..Z dan 0..9.

Apakah ada cara yang elegan untuk melakukan ini di bash sama sekali?


1
Apakah Anda ingin membatasi diri untuk ASCII atau skrip latin? Bagaimana dengan diakritik seperti aksen (é, â ...)?
Stéphane Chazelas

Terima kasih atas tindak lanjutnya. Pos asli yang diperbarui untuk klarifikasi.
ardevd

Apakah ini benar-benar perlu di bash? Apakah bahasa seperti Perl atau awk akan dilakukan?
terdon

1
Lalu mengapa tidak memanggil Perl atau Python dari bash? Apalagi dengan perl, sangat mudah menggunakannya sebagai one-liner.
terdon

2
Apakah Anda mencoba belajar atau hanya menginginkan hasilnya? Dalam kasus kedua ada banyak program yang melakukan pekerjaan seperti john the ripper ( john) dan sejenisnya, yang akan memberi Anda banyak kemungkinan.
YoMismo

Jawaban:


13

Inilah solusi bash yang menggunakan panjang yang diinginkan sebagai parameter (Anda akan melakukannya permute 5dalam kasus Anda):

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

Tapi lambat sekali. Berani saya sarankan 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;
}

Menjalankannya:

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

Bahasa tingkat tinggi menyedot kekerasan (yang pada dasarnya adalah apa yang Anda lakukan).


@ Stéphane Chazelas Terima kasih banyak untuk suntingan itu. Saya menulis kata-kata kotor, mengabaikan kutipan yang "tepat" karena tidak diperlukan dalam kasus ini, tetapi saya sangat berterima kasih atas pintasannya!
PSkocik

Saya mencoba bashsolusi Anda . Itu sangat bagus; Saya sangat menyukainya. Ini bekerja dengan baik selama sekitar 24 jam sebelum saya perhatikan sistem saya benar-benar terkunci. Mencoba sesuatu yang mirip dengan `python; dengan hasil yang serupa, meskipun itu jauh lebih cepat.
Suara

7

Di bash, Anda dapat mencoba:

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

tapi itu akan memakan waktu lama dan menghabiskan semua ingatanmu. Yang terbaik adalah menggunakan alat lain seperti 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"}}}}}'

Waspadalah itu 6 x 62 5 byte, jadi 5.496.796.992.

Anda dapat melakukan loop yang sama bash, tetapi bashmenjadi shell paling lambat di barat, itu akan memakan waktu berjam-jam:

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

(pada sistem saya, yang output pada 700 kiB / s sebagai lawan 20MiB / s dengan yang perlsetara).


Saya juga merasa bahwa itu akan menambah jawaban jika Anda ingin menambahkan cara untuk mengeluarkannya ke file; mungkin karena sedang dibuat sehingga tidak merusak RAM Anda, atau setelah itu semua di-cache dalam ram
Hellreaver

2
@ Hellreaver, mereka semua menulis ke file (ke stdout, file apa pun yang terbuka untuk; jika dijalankan di terminal, file perangkat seperti /dev/pts/something; dan Anda dapat mengubahnya dengan operator pengalihan shell), bukan memori, tetapi yang pertama dibangun seluruh output dalam memori sebelum mengeluarkannya (ke file terbuka di stdout).
Stéphane Chazelas

4

Berikut cara untuk melakukannya murni di bash tanpa harus mengisi memori 5 GB:

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

Versi bash ini masih tidak secepat Perl tetapi sekitar empat kali lebih cepat dari lima loop bersarang:

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

Anda dapat menggunakan crunch(yang tersedia setidaknya di distribusi Kali).

crunch 5 5 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890

1

Yah ... elegan ?, ya (hanya sampel cepat):

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

Ekspresi penuh ini kemungkinan besar akan memblokir komputer Anda:

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

Salah satu opsi non-blocking adalah menggunakan beberapa 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"

Sebut saja seperti:

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

Di mana argumen pertama adalah jumlah karakter dan yang kedua adalah daftar (spasi terpisah) dari karakter yang digunakan.

Itu akan membangun variabel ( loop) dengan skrip untuk menjalankan dan eval terakhir akan menjalankan skrip itu. Misalnya untuk:

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

Nilai loopakan:

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;

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.