Vic*_*tor 2 sorting random bash scripting list
以下代码列出了名称和"数字",并为每个人提供了15到90岁之间的随机年龄.
#!/bin/sh
file=$1
n=$2
# if number is zero exit
if [ "$n" -eq "0" ]
then
exit 0
fi
echo "Generating list of $n people."
for i in `seq 1 $n`;
do
let "NUM=($RANDOM%75)+15"
echo "name$i $NUM (###)###-####" >> $file
done
echo "List generated."
Run Code Online (Sandbox Code Playgroud)
有了它,我正在尝试列出1M名称.它很慢,我预料到了; 它太慢了,我失去了耐心,尝试了10K的名字.那也很慢,但它在几秒钟内就完成了.
我生成名称的原因是对它们进行排序.令我惊讶的是,当我对10K名称列表进行排序时,它是即时的.
怎么会这样?
是否有什么东西让这个变得不那么慢?排序和生成都是访问文件,那么排序如何更快?列表生成器中的随机数数学是什么减慢了它?
这是我的排序脚本.
#!/bin/sh
#first argument is list to be sorted, second is output file
tr -s '' < $1 | sort -n -k2 > $2
Run Code Online (Sandbox Code Playgroud)
使用shell生成这样的随机数并不是它的设计目的.你可能会更好地编写一些东西,用另一种语言的统一分布生成随机数,比如Fortran,Perl或C.
在你的代码中,一件非常慢的事情是从1..1e7生成一系列数字并将它们全部分配给变量.这可能非常浪费,但如果你想确定,你应该描述一下.正如混乱所指出的那样,附加到文件也可能非常昂贵!
在Python中,您可以执行以下操作:
#!/usr/bin/python
import random
count = 1
print ' '.join( ['name', 'age'] )
while count <= 1000000:
age = random.randrange(15,90)
count = count + 1
name = 'name' + str(count)
print ' '.join( [ name, str(age) ] )
Run Code Online (Sandbox Code Playgroud)
在笔记本电脑上运行需要大约10秒钟.将seq从1分配给1000000需要大约10秒,当您添加随机数生成时,您的脚本在同一台机器上花费超过三分钟.我和你一样感到沮丧,并且使用脚本来尝试让它更快.这是我正在使用的缩短版代码:
for x in `seq 1 10000`; do
let "NUM=($RANDOM%75)+15"
echo $NUM >> test.txt
done
Run Code Online (Sandbox Code Playgroud)
运行这个大概需要5.3s:
$ time ./test.sh
real 0m5.318s
user 0m1.305s
sys 0m0.675s
Run Code Online (Sandbox Code Playgroud)
删除文件追加并简单地将STDOUT重定向到单个文件提供以下脚本:
for x in `seq 1 10000`; do
let "NUM=($RANDOM%75)+15"
echo $NUM
done
Run Code Online (Sandbox Code Playgroud)
运行这个大约需要半秒钟:
$ time ./test.sh > test.txt
real 0m0.516s
user 0m0.449s
sys 0m0.067s
Run Code Online (Sandbox Code Playgroud)
程序的缓慢至少部分是由于附加到该文件.奇怪的是,当我尝试用for循环交换seq调用时,我没有注意到任何加速.
for i in `seq 1 $n`
Run Code Online (Sandbox Code Playgroud)
哎呀!这会为for循环生成1,000,000个参数.这个seq电话需要很长很长时间.尝试
for ((i = 1; i <= n; i++))
Run Code Online (Sandbox Code Playgroud)
顺便提一下,请注意缺少美元符号.特别是,var++语法要求您从变量名中省略美元符号.您也可以在其他地方使用或省略它们:它可以是i <= n或者$i <= $n任何一个.我想的样子,你应该忽略美元符号完全let,declare和for ((x; y; z))语句.有关sh完整说明,请参见手册页的ARITHMETIC EVALUATION部分.
不是新的答案,只是新的代码.
这就是恕我直言在优秀和高效的代码之间的良好中间路径(尽可能高效,你可以在Bash,它很慢,它是一个shell ...)
for ((i=1;i<=n;i++));
do
echo "name$i $((NUM=(RANDOM%75)+15)) (###)###-####"
done > "$file"
Run Code Online (Sandbox Code Playgroud)
替代方案,不使用经典的计数器循环
i=1
while ((i<=n)); do
echo "name$((i++)) $((NUM=(RANDOM%75)+15)) (###)###-####"
done > "$file"
Run Code Online (Sandbox Code Playgroud)
两者速度大致相同.
修复程序与所有其他修复程序相同: