Все возможные комбинации символов и цифр

13

Поэтому я хочу создать все возможные комбинации строчных и прописных символов и цифр, которые могут составить 5-символьную строку.

Возможности: a..z, A..Z и 0..9.

Есть ли какой-нибудь элегантный способ сделать это в bash?

ardevd
источник
1
Вы хотите ограничить себя ASCII или латинским алфавитом? А как насчет диакритических знаков, таких как акценты (é, â ...)?
Стефан Шазелас
Спасибо за продолжение. Обновлен оригинальный пост для уточнения.
ardevd
Это действительно должно быть в Bash? Подойдет ли такой язык, как Perl или awk?
Тердон
1
Тогда почему бы просто не вызвать Perl или Python из bash? Особенно perlлегко использовать его как однострочник.
Тердон
2
Вы пытаетесь учиться или просто хотите получить результат? Во втором случае есть множество программ, выполняющих эту работу, таких как john the ripper ( john) и т.п., которые предоставят вам множество возможностей.
YoMismo

Ответы:

13

Вот решение bash, которое принимает желаемую длину в качестве параметра (вы бы сделали 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

Языки высокого уровня отстой в грубой силе (что в основном то, что вы делаете).

PSkocik
источник
@ Stéphane Chazelas Большое спасибо за это редактирование. Я писал грязные, игнорируя «правильные» цитаты, так как в этом случае они не нужны, но я очень благодарен за ярлыки!
PSkocik
Я попробовал ваше bashрешение. Это очень приятно; Мне это очень нравится. Это работало хорошо в течение примерно 24 часов, прежде чем я заметил, что моя система полностью заблокирована. Пробовал что-то похожее с `python; с похожим результатом, хотя это было значительно быстрее.
голоса
7

В 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 x 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, они все записывают в файл (в стандартный вывод, в любой файл, к которому открыт доступ; при запуске в терминале, в файл устройства, например /dev/pts/something, и вы можете изменить это с помощью оператора перенаправления оболочки), не в память, а в первую сборку весь вывод в памяти перед выводом (в файл, открытый на стандартный вывод).
Стефан Шазелас
4

Вот способ сделать это чисто в bash без необходимости разбивать 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
G-Man говорит: «Восстанови Монику»
источник
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
RICi
источник
1

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

crunch 5 5 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890
user123456
источник
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;
NotAnUnixNazi
источник
1

Gnu Parallel может создавать комбинации, см. Https://www.gnu.org/software/parallel/ Примерно так:

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}
Кристофер Бархам
источник