我想在unix shell中生成一个随机文件名(例如tcshell)。文件名应包含随机的32个十六进制字母,例如:
c7fdfc8f409c548a10a0a89a791417c5
(我将在其中添加必要的内容)。关键是只能在外壳中执行此操作,而无需诉诸程序。
Answers:
假设您使用的是Linux,则应该可以进行以下操作:
cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32
这仅是伪随机的,前提是您的系统熵不足,但是(在Linux上)一定会终止。如果您需要真正随机的数据,请用cat/dev/random
代替/dev/urandom
。此更改将使您的代码处于阻塞状态,直到有足够的熵来产生真正的随机输出为止,因此可能会减慢您的代码速度。对于大多数用途,的输出/dev/urandom
是足够随机的。
如果您使用的是OS X或其他BSD,则需要将其修改为以下内容:
cat /dev/urandom | env LC_CTYPE=C tr -cd 'a-f0-9' | head -c 32
为什么不使用unix mktemp命令:
$ TMPFILE=`mktemp tmp.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` && echo $TMPFILE
tmp.MnxEsPDsNUjrzDIiPhnWZKmlAXAO8983
--dry-run
阻止创建文件的标志。那当然打开了可能的比赛条件。
正如您可能从每个答案中注意到的那样,通常必须“重新组合程序”。
但是,在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})
在下文中,“第一”和“第二”printf
指的是它们执行的顺序,而不是它们在行中出现的顺序。
此技术使用括号扩展生成32个随机数mod 16的列表,每个列表后跟一个空格,括号中范围内的数字之一,后跟另一个空格(例如11 00
)。对于该列表中的每个元素,第一个printf
使用其格式字符串(%.2
)除去除前两个字符外的所有字符,留下单个数字,后跟一个空格或两个数字。格式字符串中的空格可确保每个输出编号之间至少有一个空格。
不使用包含第一个printf
字母的命令替换来引起单词拆分,并且每个数字printf
作为单独的参数进入第二个字母。在那里,数字通过%X
格式字符串转换为十六进制,并且彼此之间不加空格地附加(因为格式字符串中没有空格),并且结果存储在名为的变量中string
。
当printf
接收到的参数超出其格式字符串所占的比例时,该格式将依次应用于每个参数,直到所有参数都被消耗为止。如果参数较少,则忽略不匹配的格式字符串(部分),但是在这种情况下不适用。
我在Bash 3.2、4.4和5.0-alpha中对其进行了测试。但这在zsh(5.2)或ksh(93u +)中不起作用,因为RANDOM
在这些shell的大括号扩展中仅被评估一次。
请注意,由于在0到32767范围内的值上使用mod运算符,使用代码段的数字分布可能会出现偏差(更不用说数字首先是伪随机的事实)。但是,由于我们使用的是mod 16,而32768可被16整除,所以在这里不会有问题。
在任何情况下,要做到这一点正确的方法是使用mktemp
在奥列格Razgulyaev的答案。
经过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
16^32
。
md5sum
二进制文件的系统。例如,FreeBSD和OSX/sbin/md5
的用途相同,但使用不同的选项语法。
第一个答案很好,但是如果不需要,为什么要叉猫。
tr -dc 'a-f0-9' < /dev/urandom | head -c32
从中抓取16个字节/dev/random
,将其转换为十六进制,采用第一行,删除地址,删除空格。
head /dev/random -c16 | od -tx1 -w16 | head -n1 | cut -d' ' -f2- | tr -d ' '
当然,假定“不求助于程序”意味着“仅使用容易获得的程序”。
od
,但不能让它做我想要的事情。fmark的答案虽然处理更多的字节,但实际上可能更快。
-w16
为-N16
)。
希望为该主题添加(也许)更好的解决方案。
注意:这仅适用于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