5

So I have this function with the following output:

    AGsg4SKKs74s62#

I need to find a way to scramble the characters without deleting anything..aka all characters must be present after I scramble them.

I can only bash utilities including awk and sed.

Bruce Strafford
  • 173
  • 4
  • 15

4 Answers4

9
echo 'AGsg4SKKs74s62#' | sed 's/./&\n/g' | shuf | tr -d "\n"

Output (e.g.):

S7s64#2gKAGsKs4
Cyrus
  • 84,225
  • 14
  • 89
  • 153
5

Here's a pure Bash function that does the job:

scramble() {
    # $1: string to scramble
    # return in variable scramble_ret
    local a=$1 i
    scramble_ret=
    while((${#a})); do
        ((i=RANDOM%${#a}))
        scramble_ret+=${a:i:1}
        a=${a::i}${a:i+1}
    done
}

See if it works:

$ scramble 'AGsg4SKKs74s62#'
$ echo "$scramble_ret"
G4s6s#2As74SgKK

Looks all right.

gniourf_gniourf
  • 44,650
  • 9
  • 93
  • 104
3

I know that you haven't mentioned Perl but it could be done like this:

perl -MList::Util=shuffle -F'' -lane 'print shuffle @F' <<<"AGsg4SKKs74s62#"

-a enables auto-split mode and -F'' sets the field separator to an empty string, so each character goes into a separate array element. The array is shuffled using the function provided by the core module List::Util.

Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
0

Here is my solution, usage: shuffleString "any-string". Performance is not in my consideration when using bash.

function shuffleString() {
    local line="$1"
    for i in $(seq 1 ${#line}); do
        local p=$(expr $RANDOM % ${#line})
        if [[ $p -lt $i ]]; then
            local line="${line:0:$p}${line:$i:1}${line:$p+1:$i-$p-1}${line:$p:1}${line:$i+1}"
        elif [[ $p -gt $i ]]; then
            local line="${line:0:$i}${line:$p:1}${line:$i+1:$p-$i-1}${line:$i:1}${line:$p+1}"
        fi
    done
    echo "$line"
}
qian Zhou
  • 1
  • 1