Всі можливі комбінації символів та цифр


13

Тому я хочу створити всі можливі комбінації символів і малих літер і цифр, які можуть складати рядок з 5 символів.

Можливості: a..z, A..Z та 0..9.

Чи взагалі є якийсь елегантний спосіб зробити це в басі?


1
Ви хочете обмежитися ASCII або латинським сценарієм? Що з діакритикою, як наголоси (é, â ...)?
Стефан Шазелас

Дякуємо за подальші дії. Оновлений оригінальний пост для уточнення.
ардевд

Чи справді потрібно бути в басі? Чи зробить таку мову, як Perl чи awk?
тердон

1
Тоді чому б просто не зателефонувати Perl чи Python з bash? Тим більше perl, що це дуже просто використовувати як однолінійний.
тердон

2
Ви намагаєтеся навчитися чи просто хочете результату? У другому випадку є безліч програм, які виконують таку роботу, як John ripper ( john) тощо), що дасть вам безліч можливостей.
YoMismo

Відповіді:


13

Ось баш-рішення, яке приймає потрібну довжину як параметр (ви б зробили permute 5у вашому випадку):

#!/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? 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;
}

Виконати:

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

Мови високого рівня смокчуть жорстокі дії (що в основному те, що ви робите).


@ Stéphane Chazelas Дякую вам дуже за цю редакцію. Я писав брудно, ігноруючи "належне" цитування, оскільки це не потрібно в цьому випадку, але я дуже вдячний за ярлики!
PSkocik

Я спробував ваше bashрішення. Це дуже приємно; Мені це дуже подобається. Він працював добре близько 24 годин або близько того, перш ніж я помітив, що моя система була повністю заблокована. Спробував щось подібне з `python; з аналогічним результатом, хоча це було значно швидше.
голоси

8

В bash, ви можете спробувати:

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

але це займе назавжди і використає всю вашу пам’ять. Найкраще було б використовувати інший інструмент на кшталт 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"}}}}}'

Остерігайтеся, що це 6 х 62 5 байт, так 5 496 796 992.

Ви можете зробити ту саму петлю bash, але, bashбудучи найповільнішою оболонкою на заході, це займе години:

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

(у моїй системі, що виводить швидкість 700 кіБ / с на відміну від 20 Мбі / с з perlеквівалентом).


Я також вважаю, що це додасть би відповіді, якби ви додали спосіб вивести його у файл; можливо, як він генерується, щоб він не знищував оперативну пам’ять, або після того, як це все
заховано

2
@Hellreaver, всі вони записують у файл (до stdout, будь-який файл, до якого відкрито; якщо він працює в терміналі, файл пристрою, як /dev/pts/something; і ви можете змінити це за допомогою оператора перенаправлення оболонки), а не пам'ять, але перший створює весь вихід у пам'яті перед виведенням його (у файл, відкритий у stdout).
Стефан Шазелас

4

Ось як це зробити чисто в башті, не вимагаючи 5 Гб пам'яті:

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

Ця версія bash все ще не така швидка, як Perl, але приблизно в чотири рази швидша, ніж п'ять вкладених циклів:

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

Ви можете використовувати crunch(який доступний принаймні у дистрибутивах Kali).

crunch 5 5 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890

1

Ну ... елегантно, так (просто швидкий зразок):

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

Цей повний вираз, швидше за все, заблокує ваш комп'ютер:

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

Один варіант, що не блокує, - це використовувати кілька циклів:

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"

Назвіть це так:

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

Де перший аргумент - кількість символів, а другий - список (пробіл) розділених символів.

Це створить змінну ( loop) із запущеним сценарієм, і останній eval виконає цей сценарій. Наприклад для:

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

Значення 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;

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.