| File: | bin/random-string | 
| Coverage: | 96.2% | 
| line | stmt | bran | cond | sub | time | code | 
|---|---|---|---|---|---|---|
| 1 | #!/usr/bin/env perl | |||||
| 2 | ||||||
| 3 | 23 23 23 | 42609 17 351 | use strict; | |||
| 4 | 23 23 23 | 32 13 494 | use warnings; | |||
| 5 | 23 23 23 | 7119 106305 36 | use Getopt::Long qw(:config no_ignore_case); | |||
| 6 | 23 23 23 | 6638 595281 1091 | use Pod::Usage; | |||
| 7 | 23 23 23 | 4930 26 16138 | use Data::Random::String::Matches; | |||
| 8 | ||||||
| 9 | 23 | 1233253 | our $VERSION = '0.02'; | |||
| 10 | ||||||
| 11 | # Parse command line options | |||||
| 12 | 23 | 77 | my %opts = ( | |||
| 13 | count => 1, | |||||
| 14 | length => undef, | |||||
| 15 | smart => 0, | |||||
| 16 | unique => 0, | |||||
| 17 | separator => "\n", | |||||
| 18 | help => 0, | |||||
| 19 | man => 0, | |||||
| 20 | version => 0, | |||||
| 21 | examples => 0, | |||||
| 22 | ); | |||||
| 23 | ||||||
| 24 | GetOptions( | |||||
| 25 | 'count|c=i' => \$opts{count}, | |||||
| 26 | 'length|l=i' => \$opts{length}, | |||||
| 27 | 'smart|s' => \$opts{smart}, | |||||
| 28 | 'unique|u' => \$opts{unique}, | |||||
| 29 | 'separator|S=s' => \$opts{separator}, | |||||
| 30 | 'help|h|?' => \$opts{help}, | |||||
| 31 | 'man|m' => \$opts{man}, | |||||
| 32 | 'version|v' => \$opts{version}, | |||||
| 33 | 'examples|e' => \$opts{examples}, | |||||
| 34 | 23 | 76 | ) or pod2usage(2); | |||
| 35 | ||||||
| 36 | # Handle special options | |||||
| 37 | 23 | 10471 | if ($opts{version}) { | |||
| 38 | 1 | 3 | print "random-string version $VERSION\n"; | |||
| 39 | 1 | 0 | exit 0; | |||
| 40 | } | |||||
| 41 | ||||||
| 42 | 22 | 28 | pod2usage(1) if $opts{help}; | |||
| 43 | 21 | 22 | pod2usage(-exitval => 0, -verbose => 2) if $opts{man}; | |||
| 44 | ||||||
| 45 | 20 | 22 | if ($opts{examples}) { | |||
| 46 | 1 | 1 | show_examples(); | |||
| 47 | 1 | 0 | exit 0; | |||
| 48 | } | |||||
| 49 | ||||||
| 50 | # Get the pattern from command line | |||||
| 51 | 19 | 40 | my $pattern = shift @ARGV; | |||
| 52 | ||||||
| 53 | 19 | 29 | unless (defined $pattern) { | |||
| 54 | 2 | 56 | print STDERR "Error: Pattern required\n\n"; | |||
| 55 | 2 | 4 | pod2usage(1); | |||
| 56 | } | |||||
| 57 | ||||||
| 58 | # Validate options | |||||
| 59 | 17 | 36 | if ($opts{count} < 1) { | |||
| 60 | 1 | 9 | die 'Error: count must be at least 1'; | |||
| 61 | } | |||||
| 62 | ||||||
| 63 | # Decode escape sequences in separator | |||||
| 64 | 16 | 25 | $opts{separator} =~ s/\\n/\n/g; | |||
| 65 | 16 | 12 | $opts{separator} =~ s/\\t/\t/g; | |||
| 66 | 16 | 15 | $opts{separator} =~ s/\\r/\r/g; | |||
| 67 | 16 | 16 | $opts{separator} =~ s/\\0/\0/g; | |||
| 68 | ||||||
| 69 | # Create generator | |||||
| 70 | 16 | 8 | my $gen = eval { | |||
| 71 | 16 | 76 | Data::Random::String::Matches->new($pattern, $opts{length}); | |||
| 72 | }; | |||||
| 73 | ||||||
| 74 | 16 | 16 | if ($@) { | |||
| 75 | 0 | 0 | die "Error creating generator: $@"; | |||
| 76 | } | |||||
| 77 | ||||||
| 78 | # Generate strings | |||||
| 79 | 16 | 10 | my @results; | |||
| 80 | 16 | 25 | for (1 .. $opts{count}) { | |||
| 81 | 25 | 15 | my $str = eval { | |||
| 82 | 25 | 40 | $opts{smart} ? $gen->generate_smart() : $gen->generate(); | |||
| 83 | }; | |||||
| 84 | ||||||
| 85 | 25 | 278 | if ($@) { | |||
| 86 | 1 | 3 | die "Error generating string: $@"; | |||
| 87 | } | |||||
| 88 | ||||||
| 89 | 24 | 40 | push @results, $str; | |||
| 90 | } | |||||
| 91 | ||||||
| 92 | # Output results | |||||
| 93 | 15 | 71 | print join($opts{separator}, @results); | |||
| 94 | 15 | 28 | print "\n" unless $opts{separator} =~ /\n$/; | |||
| 95 | ||||||
| 96 | 15 | 0 | exit 0; | |||
| 97 | ||||||
| 98 | sub show_examples { | |||||
| 99 | 1 | 2 | print <<'EXAMPLES'; | |||
| 100 | Examples: | |||||
| 101 | ||||||
| 102 | # Generate a single 4-digit number | |||||
| 103 | random-string '\d{4}' | |||||
| 104 | ||||||
| 105 | # Generate 10 API keys | |||||
| 106 | random-string 'AIza[0-9A-Za-z_-]{35}' --count 10 | |||||
| 107 | ||||||
| 108 | # Generate 5 email addresses | |||||
| 109 | random-string '[a-z]{5,10}@[a-z]{5,10}\.com' -c 5 | |||||
| 110 | ||||||
| 111 | # Generate phone numbers with custom separator | |||||
| 112 | random-string '\d{3}-\d{3}-\d{4}' -c 3 -S ', ' | |||||
| 113 | ||||||
| 114 | # Generate uppercase letters (3 characters) | |||||
| 115 | random-string '[A-Z]{3}' | |||||
| 116 | ||||||
| 117 | # Generate password-like strings | |||||
| 118 | random-string '[A-Za-z0-9!@#$%]{16}' -c 5 | |||||
| 119 | ||||||
| 120 | # Generate UUID-like strings | |||||
| 121 | random-string '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' | |||||
| 122 | ||||||
| 123 | # Use alternation | |||||
| 124 | random-string '(cat|dog|bird)' -c 10 | |||||
| 125 | ||||||
| 126 | # Use backreferences (repeating pattern) | |||||
| 127 | random-string '(\w{3})-\1' -c 5 | |||||
| 128 | ||||||
| 129 | # Generate credit card test numbers | |||||
| 130 | random-string '4\d{15}' -c 3 | |||||
| 131 | ||||||
| 132 | # Use smart mode for complex patterns (faster) | |||||
| 133 | random-string '[A-Z]{3}\d{4}' -c 100 --smart | |||||
| 134 | ||||||
| 135 | Common patterns: | |||||
| 136 | \d{4} - 4-digit PIN | |||||
| 137 | [A-Z]{2}\d{3} - License plate style | |||||
| 138 | \d{3}-\d{3}-\d{4} - Phone number | |||||
| 139 | [a-z]+@[a-z]+\.com - Simple email | |||||
| 140 | [A-Fa-f0-9]{32} - MD5 hash | |||||
| 141 | [A-Za-z0-9]{20} - Random token | |||||
| 142 | (foo|bar|baz) - One of three options | |||||
| 143 | (\w{4})-\1 - Repeated pattern | |||||
| 144 | ||||||
| 145 | EXAMPLES | |||||
| 146 | } | |||||
| 147 | ||||||