如何通过命令行获取一个由32个十六进制数字组成的随机字符串?

101

我想编写一个命令,可以打印出一个32位十六进制数字的字符串。我有一个可用的Python脚本:

python -c 'import random ; print "".join(map(lambda t: format(t, "02X"), [random.randrange(256) for x in range(16)]))'

这会生成如下输出:
6EF6B30F9E557F948C402C89002C7C8A 

我需要的是这个。

在Mac上,我甚至可以做到这一点:

uuidgen | tr -d '-'

然而,我没有使用更复杂的脚本语言Ruby和Python的权限,也没有使用Mac(因此没有uuidgen)。由于我在受限平台上操作,所以我需要坚持使用类似于Bash的工具,如sed,awk和/dev/random。是否有方法可以做到这一点?


15
也许可以尝试运行命令 head -c16 </dev/urandom|xxd -p -u?该命令会生成一个随机的16进制字符串。 - Biffen
@Biffen 我觉得这是所有解决方案中最优雅的,比任何答案都更优雅!我会使用这个,但我会将其格式化为 head -c 16 /dev/urandom | xxd -p 以提高可读性。 - undefined
如果您需要超过32位数,请将“-c 16”增加到例如“-c 32”,并使用类似于以下内容的“xxd”调用:“xxd -p -c 32”(32 = 32个八位字节,即64个十六进制字符)。 - undefined
换句话说,就像这样:head -c 32 /dev/urandom | xxd -p -c 32 - undefined
9个回答

137

如果您已经有 hexdump,那么:

hexdump -vn16 -e'4/4 "%08X" 1 "\n"' /dev/urandom

应该完成这项工作。

解释:

  • -v 用于打印所有数据(默认情况下,hexdump 通过 * 替换重复数据)。
  • -n16 用于消耗输入的 16 字节(32 个十六进制数字= 16 字节)。
  • 4/4 "%08X" 迭代四次,每次使用 4 个字节,并将相应的 32 位值打印为 8 个十六进制数字,如果需要,添加前导零。
  • 1 "\n" 以单个换行符结束。

@Renauld_Pacalet 我该如何在Python代码中实现同样的功能并生成一个32位十六进制数。当我在命令行上执行时,第一次很快,但之后由于某种原因需要30秒甚至更长时间才能完成。 - Norman Bird
4
由于/dev/random速度较慢,因此需要时间。您无法以超高吞吐量从中读取数据。这个问题解释了原因。这不是使用何种编程语言的问题,Python也会遇到同样的问题。如果您不太关心随机生成器的质量,请尝试使用/dev/urandom。但是请确保您先了解它们之间的区别。 - Renaud Pacalet
2
@RenaudPacalet:我建议你更改你的答案,使用/dev/urandom。说它是“低质量”的是一个谬论。请参见https://www.2uo.de/myths-about-urandom/。 - Jay Sullivan
@RenaudPacalet,然后默认使用urandom。因为复制粘贴的原因,我刚刚清空了我的熵池。我应该进行审核,但是,建议使用消耗如此多熵的解决方案并不常见。我强烈建议将您的答案示例命令更改为urandom(当然仍然提到两者)。 - jjmontes
use "%08x" for lower case. - Konchog

109

如果您正在寻找一个单一的命令,并且已经安装了openssl,请参见以下内容。生成随机的16个字节(32个十六进制符号)并编码为十六进制(也支持-base64)。

openssl rand -hex 16

4
好的,简洁的解决方案,但它是伪随机且使用种子文件。可能不是最安全的解决方案。请参见:https://www.openssl.org/docs/man1.0.2/man1/openssl-rand.html。 - justinpc
3
@justinpc 当你链接到文档时,它已经过时了。了解旧版本的限制是很好的,但自1.1.1版本以来就不再适用了。 - miken32

21

我知道三种方法:

#!/bin/bash

n=16 

# Read n bytes from urandom (in hex):
xxd -l "$n" -p                    /dev/urandom | tr -d " \n" ; echo
od  -vN "$n" -An -tx1             /dev/urandom | tr -d " \n" ; echo
hexdump -vn "$n" -e ' /1 "%02x"'  /dev/urandom ; echo

使用其中一个,注释掉另外两个。


4
以我的经验来看,od 是最常用的。MacOS 上有 hexdumpxddod。Git Bash(MinGW)上有 xxdod。基于 Alpine Linux 的 Docker 镜像有 od(当然还有 tr)。而且这三个平台都有 /dev/urandom。因此,如果你想要最具可移植性的解决方案,就坚持使用 od 这种方式。 - Tim Lewis

18

尝试:

xxd -u -l 16 -p /dev/urandom

示例输出:

C298212CD8B55F2E193FFA16165E95E3

并将其转换回二进制:

echo -n C298212CD8B55F2E193FFA16165E95E3 | xxd -r -p

13

以下还有几个选项,它们都具有提供明显且易于直接选择输出字符串长度的良好特性。在以下所有情况中,只需将“32”更改为所需的字符串长度即可。

#works in bash and busybox, but not in ksh
tr -dc 'A-F0-9' < /dev/urandom | head -c32

#works in bash and ksh, but not in busybox
tr -dc 'A-F0-9' < /dev/urandom | dd status=none bs=1 count=32

#works in bash, ksh, AND busybox! w00t!
tr -dc 'A-F0-9' < /dev/urandom | dd bs=1 count=32 2>/dev/null

编辑:在不同的shell中进行了测试。


1
这里的其他方法都允许您指定长度,除了字节数=字符数的一半。您可以轻松地将它们导入head -c以将其缩小到奇数。 - Rup
你的解决方案与 openssl rand -hex 16 相比效率如何? - Roland
注意:在BSD / macOS上,您需要设置LC_ALL=C,否则tr将尝试根据您的语言设置解释输入(这将导致tr: illegal byte sequence)。因此,完整的命令是:LC_ALL=C tr -dc 'A-F0-9' < /dev/urandom | head -c64 - UloPe

1

你也可以像这样使用od命令

od -N32 -x < /dev/urandom | head -n1 |  cut -b9- | sed 's/ //gi'

祝你好运


0

这里有一个不使用dev/random的版本:

awk -v len=32 'BEGIN {
    srand('$RANDOM');
    while(len--) {
        n=int(rand()*16);
        printf("%c", n+(n>9 ? 55 : 48));
    };}'

0
如果您想生成任意长度的输出,包括偶数/奇数个字符
cat /dev/urandom | hexdump --no-squeezing -e '/1 "%x"' | head -c 31

或者为了最大化效率而不是可读性/可组合性:

hexdump --no-squeezing -e '/1 "%x"' -n 15 /dev/urandom

0

纯粹的

介绍

如果你的目标是获取一个变量,并且想要快速、消耗更少的资源,那么你可能想避免使用forks。(var=$(python ..)

因此,最快的方法是使用内置函数

从5.1版本开始,bash提供了一个32位长度的$SRANDOM伪随机变量:

   SRANDOM
          This variable expands to a 32-bit pseudo-random number  each  time
          it  is  referenced.  The  random number generator is not linear on
          systems that support /dev/urandom or arc4random, so each  returned
          number  has no relationship to the numbers preceding it...

严格32个十六进制数字。

32个十六进制数字的随机字符串

你需要一堆 4 x 32 = 128 位 -> 4 x $SRANDOM 扩展

mkrand32(){
    local -n resvar=$1
    local _i _str _part
    resvar=""
    for _i in {1..4};do
         printf -v part '%08x' $SRANDOM
         resvar+=${part}
    done
}

这个需要1个参数:您想要设置的变量名:

mkrand32 varname
echo $varname
d2fd20aad1b9dad4d57c478affa8503e

相同但不限于32位数:

mkrand () { 
    local -i _i=32 _p
    [[ $1 == -l ]] && _i=$2 && shift 2
    local -n resvar=$1
    local _str _part
    resvar=""
    for ((_p=_i; _p>0; _p-=8)); do
        printf -v part '%08x' $SRANDOM
        resvar+=${part}
    done
    resvar=${resvar::_i}
}

与之前相同:默认为32位数字,但可以通过-l开关进行修改:

mkrand test
echo ${#test} $test
32 70105167a19bea5a24c5e36571446f83

mkrand -l 23 test
23 7ce93dd418aacf5bbbaace6

mkrand -l 128 test
echo ${#test} $test
128 5f0707dd58f652f55d048305377be9686d5adaec26176dcedfa1505c457b90b25c13e4a9b61bbe880ad31bca89d3c8d0433f5219cebf159925059318f7047fec

注意:这里不使用getopts,因此-l 必须通过空格分隔为数字

带选项的完整函数

您可以在我的网站上(而非GitHub)找到{{link1:mkrand的完整版本}}({{link2:mkrand.bash}})源脚本。

一旦加载:

Usage: mkrand [-h] [-a|-d|-x] [-d [-m int]] [-v varname]
  -h       Show this.
  -a       Alternative set of 64 chars ( alpha numerics + % + # )
  -d       Digits only
  -x       Hexadecimal characters (default)
  -l int   Length of generated srting (without separators)
  -m int   Mask for separators (default 0x888800: 1<<23|1<<19|1<<15|1<<11)
  -s char  Character to be user as separator (default "-")
  -v name  Variable name to be populated instead of print to STDOUT
Without argument mkrand will print UUID like 32 hexadecimal string.
  513ee11e-d6cc-b7b1-8fd9-3462675e93d5
With `-m 0` or `-s ''`, noseparator will by added.
Mask for separator is a binary value, used to determine where to insert dash.
To generate an alpha numeric string of 30 characters, separated every 5 char:
  mkrand -al30 -m0x1084210 -s' '
  3PiQo 9RXFn NIi#7 %spWG HREhx wNamf
A string of 7 bunch of 6 digits, separated by a spaced dash:
  mkrand -d -l 42 -m 0x820820820 -s ' - '
  941908 - 240445 - 797528 - 631958 - 635053 - 160422 - 92710
mkrand
8eea4296-ffda-ee9a-6fbe-a349c0d7ff18

mkrand -al 54 -m0xaaaaaaaaaaaaa
tF-Zs-r7-bS-3D-AR-m2-S0-GC-lC-SU-k2-Zk-4f-eG-5f-qa-6f-vV-wV-Wc-zA-5Z-dC-Yg-Oz-w6

mkrand -m0
c751eb64b899448a06cf7391d2a009a9

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接