所以我有这个语法如下的脚本:
./script number file
其中 number 是我想从文件 file 中获取的行数。这些行是随机选择的,然后打印两次。考虑到一个非常大的文件 ~ 1 000 000 行,此算法运行速度太慢。我不知道为什么,因为打印只包含访问数组。
#!/bin/bash
max=`wc -l $2 | cut -d " " -f1`
users=(`shuf -i 0-$max -n $1`)
pages=(`shuf -i 0-$max -n $1`)
readarray lines < $2
for (( i = 0; i < $1; i++ )); do
echo L ${lines[${users[i]}]} ${lines[${pages[i]}]}
done
for (( i = 0; i < $1; i++ )); do
echo U ${lines[${users[i]}]} ${lines[${pages[i]}]}
done
最佳答案
只需使用 shuf
来选择行,这就是它的设计目的。例如(见注释):
readarray users < <(shuf -n $1 "$2")
readarray pages < <(shuf -n $1 "$2")
for (( i = 0; i < $1; i++ )); do
echo L ${users[i]} ${pages[i]}
done
for (( i = 0; i < $1; i++ )); do
echo U ${users[i]} ${pages[i]}
done
这仍然会很慢,因为 shuf
需要读取整个文件才能找到行尾,而且您要调用它两次,但它可能比读取将整个文件作为 bash 数组存入内存,尤其是当您没有足够的可用内存时。 (如果脚本的第二个参数不是常规文件,它也不会工作;如果它是管道,则不能读取它两次。)
您可以通过同时选择两组行然后将它们分为 users
和 pages
来加快速度,但是您需要做一些工作才能获得无偏分布,假设您关心这一点。
注1:
正如@gniourf_gniourf 在评论中指出的那样,通过对 readarray
使用 -t
选项,然后将参数引用到回显
。此外,mapfile
是 readarray
的首选名称:
mapfile -t users < <(shuf -n $1 "$2")
mapfile -t pages < <(shuf -n $1 "$2")
for (( i = 0; i < $1; i++ )); do
echo L "${users[i]}" "${pages[i]}"
done
for (( i = 0; i < $1; i++ )); do
echo U "${users[i]}" "${pages[i]}"
done
注2:
如果 $1
很大,您最好不要使用数组。这是一种可能的解决方案:
lines="$(paste -d' ' <(shuf -n $1 "$2") <(shuf -n $1 "$"))"
sed 's/^/L /' <<<"$lines"
sed 's/^/U /' <<<"$lines"
关于performance - 从文件中选择随机行在 BASH 中花费的时间太长,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26830677/