我想在unix shell中生成一个随机文件名(比如tcshell)。文件名应包含随机的32个十六进制字母,例如:
c7fdfc8f409c548a10a0a89a791417c5
(我将添加任何必要的内容)。关键是能够在shell中完成而无需诉诸程序。
答案 0 :(得分:115)
假设您使用的是Linux,则以下内容应该有效:
cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32
如果你的系统在熵上运行不足,这只是伪随机的,但是(在linux上)保证终止。如果您需要真正随机的数据,请/dev/random
而不是/dev/urandom
。此更改将使您的代码阻塞,直到有足够的熵可用于生成真正的随机输出,因此可能会降低代码速度。对于大多数用途,/dev/urandom
的输出足够随机。
如果您使用OS X或其他BSD,则需要将其修改为以下内容:
cat /dev/urandom | env LC_CTYPE=C tr -cd 'a-f0-9' | head -c 32
答案 1 :(得分:41)
为什么不使用unix mktemp命令:
$ TMPFILE=`mktemp tmp.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` && echo $TMPFILE
tmp.MnxEsPDsNUjrzDIiPhnWZKmlAXAO8983
答案 2 :(得分:19)
一个命令,没有管道,没有循环:
hexdump -n 16 -v -e '/1 "%02X"' -e '/16 "\n"' /dev/urandom
如果您不需要换行符,例如当您在变量中使用换行符时:
hexdump -n 16 -v -e '/1 "%02X"' /dev/urandom
使用“16”生成32位十六进制数字。
答案 3 :(得分:6)
正如您可能从每个答案中注意到的那样,您通常 来“诉诸程序”。
但是,在Bash和ksh中不使用任何外部可执行文件:
string=''; for i in {0..31}; do string+=$(printf "%x" $(($RANDOM%16)) ); done; echo $string
zsh中的:
string=''; for i in {0..31}; do string+=$(printf "%x" $(($RANDOM%16)) ); dummy=$RANDOM; done; echo $string
将格式字符串中的小写x
更改为大写X
,以使字母十六进制字符为大写。
这是在Bash中执行此操作的另一种方法,但没有显式循环:
printf -v string '%X' $(printf '%.2s ' $((RANDOM%16))' '{00..31})
在下文中,“first”和“second”printf
指的是执行它们的顺序,而不是它们在行中出现的顺序。
此技术使用大括号展开来生成32个随机数的列表,每个随机数为16,后面跟一个空格,其中一个数字在括号中,后跟另一个空格(例如11 00
)。对于该列表的每个元素,第一个printf
使用其格式字符串(%.2
)除去前两个字符以外的所有字符,留下单个数字后跟每个或两个数字的空格。格式字符串中的空格确保每个输出编号之间至少有一个空格。
未引用包含第一个printf
的命令替换,以便执行分词,并且每个数字作为单独的参数转到第二个printf
。在那里,数字被%X
格式字符串转换为十六进制,并且它们彼此附加而没有空格(因为格式字符串中没有任何空格),结果存储在名为{{1的变量中}}
当string
收到的参数多于其格式字符串占用的参数时,格式将依次应用于每个参数,直到它们全部消耗完为止。如果参数较少,则忽略不匹配的格式字符串(部分),但在这种情况下不适用。
我在Bash 3.2,4.4和5.0-alpha中进行了测试。但它在zsh(5.2)或ksh(93u +)中不起作用,因为printf
仅在这些shell的大括号扩展中被评估一次。
请注意,由于在0到32767范围内使用mod运算符,使用代码段的数字分布可能会有所偏差(更不用说数字伪随机的事实了第一名)。但是,由于我们使用mod 16和32768可以被16整除,所以这不会有问题。
在任何情况下,正确的方法是使用RANDOM
,如 Oleg Razgulyaev的答案。
答案 4 :(得分:5)
在zsh中测试,应该与任何BASH兼容的shell一起使用!
#!/bin/zsh
SUM=`md5sum <<EOF
$RANDOM
EOF`
FN=`echo $SUM | awk '// { print $1 }'`
echo "Your new filename: $FN"
示例:
$ zsh ranhash.sh
Your new filename: 2485938240bf200c26bb356bbbb0fa32
$ zsh ranhash.sh
Your new filename: ad25cb21bea35eba879bf3fc12581cc9
答案 5 :(得分:3)
另一种方式[tm]。
R=$(echo $RANDOM $RANDOM $RANDOM $RANDOM $RANDOM | md5 | cut -c -8)
FILENAME="abcdef-$R"
答案 6 :(得分:3)
这个答案与fmarks非常相似,所以我真的不能相信它,但我发现cat和tr命令组合相当慢,我发现这个版本的速度要快得多。你需要hexdump。
hexdump -e '/1 "%02x"' -n32 < /dev/urandom
答案 7 :(得分:2)
第一个答案是好的但如果不需要叉子猫为什么。
tr -dc 'a-f0-9' < /dev/urandom | head -c32
答案 8 :(得分:1)
从/dev/random
抓取16个字节,将它们转换为十六进制,取第一行,删除地址,删除空格。
head /dev/random -c16 | od -tx1 -w16 | head -n1 | cut -d' ' -f2- | tr -d ' '
当然,假设“不使用程序”意味着“只使用随时可用的程序”。
答案 9 :(得分:1)
希望为此主题添加(可能)更好的解决方案。
注意:这仅适用于bash4
和mktemp
的某些实现(例如,GNU版本)
试试这个
fn=$(mktemp -u -t 'XXXXXX')
echo ${fn/\/tmp\//}
这个速度是head /dev/urandom | tr -cd 'a-f0-9' | head -c 32
的两倍,是cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32
的八倍。
基准:
使用mktemp:
#!/bin/bash
# a.sh
for (( i = 0; i < 1000; i++ ))
do
fn=$(mktemp -u -t 'XXXXXX')
echo ${fn/\/tmp\//} > /dev/null
done
time ./a.sh
./a.sh 0.36s user 1.97s system 99% cpu 2.333 total
另一个:
#!/bin/bash
# b.sh
for (( i = 0; i < 1000; i++ ))
do
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 32 > /dev/null
done
time ./b.sh
./b.sh 0.52s user 20.61s system 113% cpu 18.653 total
答案 10 :(得分:1)
如果您使用的是Linux,那么Python将会预先安装。所以你可以选择类似下面的东西:
python -c "import uuid; print str(uuid.uuid1())"
如果您不喜欢破折号,请使用替换功能,如下所示
python -c "import uuid; print str(uuid.uuid1()).replace('-','')"
答案 11 :(得分:0)
Another thing you can add is running the date command as follows:
date +%S%N
Reads nonosecond time and the result adds a lot of randomness.
答案 12 :(得分:0)
如果您的系统中有openssl
,则可以使用它来生成具有定义长度的随机十六进制(也可以是-base64
)字符串。我发现它在cron中非常简单,并且可以在一行作业中使用。
openssl rand -hex 32
8c5a7515837d7f0b19e7e6fa4c448400e70ffec88ecd811a3dce3272947cb452
答案 13 :(得分:0)
uuidgen
完全生成此内容,除了必须删除连字符。因此,我发现这是实现这一目标的最优雅的方法(至少对我而言)。它应该可以在Linux和OS X上使用。
uuidgen | tr -d '-'