Tüm olası karakter ve sayı kombinasyonları


13

Bu yüzden küçük ve büyük harf karakterlerin ve sayıların 5 karakter dizesini oluşturabilecek tüm olası kombinasyonlarını oluşturmak istiyorum.

Olasılıklar: a..z, A..Z ve 0..9.

Bunu bash'da yapmanın zarif bir yolu var mı?


1
Kendinizi ASCII veya latin alfabesiyle sınırlamak ister misiniz? Aksanlar gibi aksanlara ne dersiniz (é, â ...)?
Stéphane Chazelas

Takip için teşekkürler. Açıklama için orijinal yayın güncellendi.
ardevd

Gerçekten bashta olması gerekiyor mu? Perl veya awk gibi bir dil işe yarar mı?
terdon

1
Öyleyse neden sadece Perl veya Python'u bash'tan aramıyorsunuz? Özellikle perltek astar olarak kullanmak çok kolaydır.
terdon

2
Öğrenmeye mi çalışıyorsunuz yoksa sadece sonucu mı istiyorsunuz? İkinci durumda, işi ripper john ( john) ve benzeri gibi yapan, size birçok olasılık sağlayacak birçok program vardır.
YoMismo

Yanıtlar:


13

Parametre olarak istenen uzunluğu alan bir bash çözümü ( permute 5sizin durumunuzda yapacağınız ):

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

Yine de acı verici yavaş. C tavsiye 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;
}

Çalıştır:

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

Yüksek seviyeli diller kaba kuvvet zorlar (temelde yaptığınız şeydir).


@ Stéphane Chazelas Bu düzenleme için çok teşekkür ederim. Kirli yazıyordum, bu durumda gerekli olmadığı için "uygun" alıntıları görmezden geliyordum, ama kısayollar için çok minnettarım!
PSkocik

bashÇözümünü denedim . Bu çok hoş; Onu çok severim. Sistemimin tamamen kilitli olduğunu fark etmeden önce yaklaşık 24 saat iyi çalıştı. Python ile benzer bir şey denedim; benzer bir sonuçla birlikte, oldukça hızlı olmasına rağmen.
sesler

8

In bash, deneyebilirsiniz:

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

ama bu sonsuza dek sürecek ve tüm hafızanızı kullanacak. En iyisi şu gibi başka bir araç kullanmak olacaktır 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"}}}}}'

Dikkat edin 6 x 62 5 bayt, yani 5.496.796.992.

Aynı döngüyü içeri sokabilirsiniz bash, ancak bashbatıdaki en yavaş kabuk olmak, saatler sürecek:

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

(benim sistemimde, eşdeğeri 20MiB / s yerine 700 kiB / s çıktı perl).


Ben de bir dosyaya çıktı için bir yol eklemek olsaydı cevaba eklemek olacağını hissediyorum; belki de üretildiği için
RAM'inizi

2
@Hellreaver, hepsi bir dosyaya yazar (stdout'a, açık olan herhangi bir dosya; bir terminalde çalıştırılırsa, bir cihaz dosyası gibi /dev/pts/something; ve bunu kabuk yeniden yönlendirme operatörü ile değiştirebilirsiniz), ancak bellek değil, birincisi çıkıştan önce bellekteki tüm çıktı (stdout'ta açık olan dosyaya)
Stéphane Chazelas

4

İşte 5 GB bellek kesmek zorunda kalmadan tamamen bash'da yapmanın bir yolu:

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

Bu bash sürümü hala Perl kadar hızlı değil, ancak beş iç içe döngüden yaklaşık dört kat daha hızlı:

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

Kullanabilirsiniz crunch(en azından Kali dağıtımlarında bulunur).

crunch 5 5 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890

1

Peki ... zarif ?, evet (sadece hızlı bir örnek):

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

Bu tam ifade büyük olasılıkla bilgisayarınızı engelleyecektir:

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

Engellemeyen seçeneklerden biri birkaç döngü kullanmaktır:

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"

Şöyle çağırın:

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

İlk argüman karakter sayısı ve ikincisi kullanılan karakterlerin listesidir (boşlukla ayrılır).

Bu, loopçalıştırılacak komut dosyasıyla bir değişken ( ) oluşturur ve son değerlendirme bu komut dosyasını yürütür. Örneğin:

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

Değeri loop:

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;

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.