在unix shell中生成一个随机文件名


76

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

c7fdfc8f409c548a10a0a89a791417c5

(我将在其中添加必要的内容)。关键是只能在外壳中执行此操作,而无需诉诸程序。


Answers:


126

假设您使用的是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

1
@LukeN:你的很好。从技术上讲,不能保证此解决方案会终止:)
总统James K. Polk 2010年

1
这个解决方案实际上对我来说很奇怪,因为它在实际的随机哈希值后面附加了一个白色背景的“%”符号,但是由于我的shell通常在某些情况下表现出怪异,所以我不想让它看起来很糟糕它被接受了:)
路加福音

1
我在具有/ dev / urandom的Mac上尝试了此操作。在bash shell中执行命令会导致错误-'tr:非法字节序列'
Gareth Stockwell,2010年

5
我认为这里的问题是BSD和Mac将字符串解释为多字节而不是单字节。我没有机器可以尝试此操作,因此如果可行,请在此处报告:cat / dev / urandom | env LC_CTYPE = C tr -cd'a-f0-9'| 头-c 32
fmark

2
看起来像是对猫的另一种无用的用法:-)
詹斯(Jens)2012年


21

一个命令,没有管道,没有循环:

hexdump -n 16 -v -e '/1 "%02X"' -e '/16 "\n"' /dev/urandom

如果不需要换行符,例如在变量中使用换行符时:

hexdump -n 16 -v -e '/1 "%02X"' /dev/urandom

使用“ 16”将生成32个十六进制数字。


这太棒了。我从没想过要用hexdump那个。
avetisk

7

正如您可能从每个答案中注意到的那样,通常必须“重新组合程序”。

但是,在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的答案。


1
谢谢丹尼斯,它帮助了我。.我只是将字符串设置为空,这样字符串的长度总是按预期在每次重新运行同一脚本时追加。在{0..5}中;执行string + = $(printf“%x” $((($ RANDOM%16))));完成;回显$ string); 回声“随机ID值为$ {randomId}”
Santosh Kumar Arjunan

@SantoshKumarA:感谢您指出该变量需要初始化。我将其添加到答案中。我还添加了另一种有趣的技术及其解释。
丹尼斯·威廉姆森

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

1
这样只会生成32768个唯一的文件名,而不是16^32
丹尼斯·威廉姆森

这也仅适用于包含md5sum二进制文件的系统。例如,FreeBSD和OSX/sbin/md5的用途相同,但使用不同的选项语法。
ghoti

4

另一种方式[tm]。

R=$(echo $RANDOM $RANDOM $RANDOM $RANDOM $RANDOM | md5 | cut -c -8)
FILENAME="abcdef-$R"

大多数系统上可用的程序是md5sum。我喜欢这种解决方案,因为如果您不需要高随机性,则只能使用一次$ RANDOM,这使它成为最简短易读的解决方案。

a)如果您有md5sum,则可以用md5sum替换md5并相应地更新切割。b)仅使用一个$ RANDOM是危险的,它仅产生0到32767之间的值,这要短得多,具体取决于应用程序。
2014年

3

这个答案与fmarks非常相似,所以我不能真正相信它,但是我发现cat和tr命令的组合非常慢,而且我发现这个版本要快得多。您需要hexdump。

hexdump -e '/1 "%02x"' -n32 < /dev/urandom

高手。使用-n16大约32个字符。
Walf


2

uuidgen完全生成此代码,除了必须删除连字符。因此,我发现这是实现这一目标的最优雅的方法(至少对我而言)。它应该可以在Linux和OS X上使用。

uuidgen | tr -d '-'

1

从中抓取16个字节/dev/random,将其转换为十六进制,采用第一行,删除地址,删除空格。

head /dev/random -c16 | od -tx1 -w16 | head -n1 | cut -d' ' -f2- | tr -d ' '

当然,假定“不求助于程序”意味着“仅使用容易获得的程序”。


我测试了一下。它比其他解决方案慢很多,但确实有效。
aarona

是的,对于类似这样的简单操作来说,这是一个相当长的管道。我希望在上有更多的标志od,但不能让它做我想要的事情。fmark的答案虽然处理更多的字节,但实际上可能更快。
托马斯(Thomas)

1
如果使用/ dev / urandom而不是/ dev / random,它将更快
fmark 2010年

fmark是正确的,这里可能是/ dev / random部分,因为/ dev / random是一个真正的随机数生成器,当不再有熵时将阻塞:)
LukeN 2010年

此解决方案绝对是最便携的解决方案!它甚至可以在最新的Android上运行(除非您应替换-w16-N16)。
user1643723 '16

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

1

如果您使用的是Linux,则将预安装Python。因此,您可以进行类似于以下的操作:

python -c "import uuid; print str(uuid.uuid1())"

如果您不喜欢破折号,请使用如下所示的替换功能

python -c "import uuid; print str(uuid.uuid1()).replace('-','')"

0

您可以添加的另一件事是运行date命令,如下所示:

date +%S%N

读取非秒时间,结果增加了很多随机性。


0

如果您openssl的系统中有,则可以使用它来生成-base64具有定义长度的随机十六进制(也可以是)字符串。我发现它在cron中非常简单,并且可以在一行作业中使用。

 openssl rand -hex 32
 8c5a7515837d7f0b19e7e6fa4c448400e70ffec88ecd811a3dce3272947cb452
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.