如何在bash中打乱字符串的字符?

如何在bash中打乱字符串的字符?

我有这个脚本,它会生成随机密码,但需要对其进行洗牌。我找不到办法做到这一点。请帮我。

num=("0" "1" "2" "3" "4" "5" "7" "8" "9")
special=("@" "#" "$" "%" "*" "-" "+")
upper=(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
lower=(a b c d e f g h i j k l m n o p q r s t u v w x y z)
lower2=${#lower[*]}   #${lower[$((RANDOM%lower2))]}
upper2=${#upper[*]}   #${upper[$((RANDOM%upper2))]}
num2=${#num[*]}     #${num[$((RANDOM%num2))]}
special2=${#special[*]} #${special[$((RANDOM%special2))]}
echo "${special[$((RANDOM%special2))]}${num[$((RANDOM%num2))]}${lower[$((RANDOM%lower2))]}${upper[$((RANDOM%upper2))]}${lower[$((RANDOM%lower2))]}${upper[$((RANDOM%upper2))]}${lower[$((RANDOM%lower2))]}${upper[$((RANDOM%upper2))]}"

这是输出:@7nOyIaJ 如何随机化它?

答案1

我假设你希望它是随机的,因为“特殊”总是第一位的。这是一个巨大的 hacky 方法。笔记:你的脚本是scr.bash.

$ echo $(./scr.bash | fold -w1 | shuf | tr -d '\n')

例子

$ echo $(./scr.bash | fold -w1 | shuf | tr -d '\n')
qT*Jyv8Y

$ echo $(./scr.bash | fold -w1 | shuf | tr -d '\n')
QbOvX3n-

$ echo $(./scr.bash | fold -w1 | shuf | tr -d '\n')
*Q5nGgIt

这很粗糙,但向您展示了方法。

细节

fold命令会将输出分成每行 1 个字符。还有其他方法可以做到这一点,但我选择了fold。该shuf命令可以将行“打乱”成随机顺序。该命令将从我们所做的初始折叠中tr删除换行符 ( )。\n

答案2

@slm 给出的答案很好地利用了 shell 中可用的工具,但与“scr.bash”结合使用时有点复杂。如果您有 Python(版本 2.7 或 3.x),这里有一个脚本可以更容易地完成相同的工作:

#!/usr/bin/env python
"""
Create a formulaic but reasonably strong password.
"""

import random

def shuffled_password():
    """Using one random member of special and num and three members each
       from upper and lower return a shuffled string of their concatenation.
    """
    num = list('012345789')
    special = list('@#$%*-+')
    upper = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
    lower = list('abcdefghijklmnopqrstuvwxyz')
    random.shuffle(num)
    random.shuffle(special)
    random.shuffle(upper)
    random.shuffle(lower)

    letters = [special[0], num[0]]
    letters.extend(lower[0:3] + upper[0:3])
    random.shuffle(letters)
    s = ''.join(letters)  # funny way to turn list of chars into string
    return s

if __name__ == '__main__':
    print(shuffled_password())

我在探索您的方法的组合复杂性的过程中编写了这段代码。上面有人提到使用pwgen;我一开始以为它一定比你自制的方法强,但我的猜测是错误的。

即使没有,你的方法也会shuffle(letters)产生 210 亿个组合。这会产生一个估计熵39 位。这从强度测试中得到了非正式的评级:

36 - 59 位 = 合理;相当安全的网络密码和公司密码

添加最后的随机播放会向混合中添加大约 5 位熵。以供参考,

pwgen --symbols --numerals

生成估计熵为 37 位的密码。我将此归因于 pwgen 尝试生成“可记忆”的密码,从而以某种方式减少了输出集。根据强度测试的类别,这仍然是“合理的”。

注意:我的组合数学,特别是在多重排列中,是有限的,欢迎更正。

答案3

纯 Bash解决方案也适用于多字节 UTF-8 字符,如果区域设置正确(例如LANG=C.UTF-8)。

我们简单地使用字符串操作和一些bash 友好的算法,例如费舍尔-耶茨洗牌:

# shuffle() - shuffle  a string
# $1: The string to shuffle
#
# The string is shuffled using the Fisher–Yates shuffle method :
# https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
#
# @return: 0,  output the shuffled string to stdout.
shuffle() {
    local _str="$1" _res
    local -i _i _cur

    for (( _i = ${#_str} ; _i > 0; --_i )); do
        _cur=$((SRANDOM % _i))
        _res+=${_str:$_cur:1}
        _str="${_str:0:_cur}${_str:_cur+1}"
    done
    printf "%s" "$_res"
}

结果 :

$ for i in {1..5}; do echo $(shuffle "@7nOyIaJ"); done
@IJn7Oay
Oa7Jn@yI
Oa@n7IJy
JaO7ny@I
OJI@n7ay
$ for i in {1..5}; do printf "%s\n" $(shuffle "abc山藤123Å"); done
2bca13藤Å山
Åc13藤a山2b
a2b山1c3Å藤
1a3b藤2cÅ山
山3Åc1a2藤b

答案4

我相信最简单的方法是(来源):

echo "

相关内容