文字と数字のすべての可能な組み合わせ


13

したがって、5文字の文字列を構成できる小文字と大文字のすべての可能な組み合わせを生成したいと思います。

可能性:a..z、A..Zおよび0..9。

bashでこれを行うエレガントな方法はありますか?


1
ASCIIまたはラテンスクリプトに制限しますか?アクセント(é、â...)などの発音区別記号はどうですか?
ステファンシャゼラス

フォローアップしていただきありがとうございます。明確化のために元の投稿を更新しました。
ardevd

それは本当にbashにいる必要がありますか?Perlやawkのような言語は機能しますか?
テルドン

1
次に、bashからPerlまたはPythonを呼び出すだけではどうですか?特にでperl、ワンライナーとして使用するのは非常に簡単です。
テルドン

2
学習しようとしているのですか、それとも結果を望んでいますか?2番目のケースでは、ジョン・ザ・リッパー(john)などの仕事をするプログラムがたくさんあります。
ヨミスモ

回答:


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

高レベルの言語は、総当たり攻撃(基本的にはあなたがしていることです)を嫌います。


@StéphaneChazelas編集ありがとうございます。この場合は必要ないので、「適切な」引用を無視して、汚い文章を書いていましたが、ショートカットにとても感謝しています!
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

(私のシステムでは、perl同等の20MiB / sではなく700kiB / sで出力します)。


また、ファイルに出力する方法を追加すると、答えに追加されると思います。多分、RAMを破壊しないように生成されているか、RAMにすべてキャッシュされた後
Hellreaver

2
@Hellreaver、それらはすべてファイルに書き込みます(開いているファイルはすべて標準出力に、端末で実行する場合はデバイスファイルなど/dev/pts/something、シェルリダイレクト演算子で変更できます)、メモリではなく、最初のビルド(stdoutで開いているファイルに)出力する前に、メモリ内の出力全体。
ステファンシャゼル

4

これは、5 GBのメモリを浪費することなく、純粋にbashで実行する方法です。

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ほど高速ではありませんが、5つのネストされたループの約4倍の速度です。

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}}'{,,,,} )

ノンブロッキングオプションの1つは、複数のループを使用することです。

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

ここで、最初の引数は文字数で、2番目は使用する文字のリスト(スペース区切り)です。

これ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;

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.