在unix shell中生成随机文件名

时间:2010-05-08 11:06:47

标签: unix shell random tcsh

我想在unix shell中生成一个随机文件名(比如tcshell)。文件名应包含随机的32个十六进制字母,例如:

c7fdfc8f409c548a10a0a89a791417c5

(我将添加任何必要的内容)。关键是能够在shell中完成而无需诉诸程序。

14 个答案:

答案 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)

希望为此主题添加(可能)更好的解决方案。

注意:这仅适用于bash4mktemp的某些实现(例如,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 '-'