Bash 使用sed的随机线
我想用Bash 使用sed的随机线,bash,sed,Bash,Sed,我想用sed随机选择一行。我知道shuf-n和sort-R | head-n可以完成这项工作,但是对于shuf您必须安装coreutils,对于排序解决方案来说,它在大数据上不是最优的: 以下是我测试的内容: echo "$var" | shuf -n1 这提供了最佳解决方案,但我担心可移植性 这就是为什么我想用sed试试它 `var="Hi i am a student learning scripts"` output: i am a student output: hi 它一定
sed
随机选择一行。我知道shuf-n
和sort-R | head-n
可以完成这项工作,但是对于shuf
您必须安装coreutils
,对于排序解决方案来说,它在大数据上不是最优的:
以下是我测试的内容:
echo "$var" | shuf -n1
这提供了最佳解决方案,但我担心可移植性
这就是为什么我想用sed
试试它
`var="Hi
i am a student
learning scripts"`
output:
i am a student
output:
hi
它一定是随机的
var="Hi
i am a student
learning scripts"
mapfile -t array <<< "$var" # create array from $var
echo "${array[$RANDOM % (${#array}+1)]}"
echo "${array[$RANDOM % (${#array}+1)]}"
请参阅:帮助映射文件
它在很大程度上取决于您希望伪随机概率分布的外观。(不要尝试随机,满足于伪随机。如果你成功地生成了一个真正的随机值,就去领取诺贝尔奖。)如果你只是想要一个均匀分布(例如,每行被选中的概率相等),那么你需要事先知道文件中有多少行。获得该分发版并不像允许选择文件中较早的行那样容易,因为这很容易,所以我们将这样做。假设行数小于32769,您只需执行以下操作:
N=$(wc -l < input-file)
sed -n -e $((RANDOM % N + 1))p input-file
$ echo -e $var >varfile
$ i=;while read a; do let i++;done<varfile; let RANDOM=i*i*i
$ let l=$RANDOM%$i+1 ;sed -En "$l p" varfile
N=$(wc-l
--编辑--
在考虑了一会儿之后,我意识到你不需要知道行数,所以你不需要读取数据两次。我没有做过严格的分析,但我相信下面给出了一个统一的分布:
awk 'BEGIN{srand()} rand() < 1/NR { out=$0 } END { print out }' input-file
awk'BEGIN{srand()}rand()<1/NR{out=$0}END{print out}输入文件
--编辑--
Ed Morton在评论中建议我们只能调用rand()一次。这似乎应该行得通,但似乎行不通。好奇的:
$ time for i in $(seq 400); do awk -v seed=$(( $(date +%s) + i)) 'BEGIN{srand(seed); r=rand()} r < 1/NR { out=$0 } END { print out}' input; done | awk '{a[$0]++} END { for (i in a) print i, a[i]}' | sort
1 205
2 64
3 37
4 21
5 9
6 9
7 9
8 46
real 0m1.862s
user 0m0.689s
sys 0m0.907s
$ time for i in $(seq 400); do awk -v seed=$(( $(date +%s) + i)) 'BEGIN{srand(seed)} rand() < 1/NR { out=$0 } END { print out}' input; done | awk '{a[$0]++} END { for (i in a) print i, a[i]}' | sort
1 55
2 60
3 37
4 50
5 57
6 45
7 50
8 46
real 0m1.924s
user 0m0.710s
sys 0m0.932s
$time for i,单位为$(seq 400);do awk-v seed=$($(date+%s)+i))'开始{srand(seed);r=rand()}r<1/NR{out=$0}结束{print out}'输入;完成| awk'{a[$0]+}END{for(a中的i)print i,a[i]}排序
1 205
2 64
3 37
4 21
5 9
6 9
7 9
8 46
实0m1.862s
用户0m0.689s
系统0m0.907s
以美元表示的i的时间(seq 400);do awk-v seed=$($(date+%s)+i))'BEGIN{srand(seed)}rand()<1/NR{out=$0}END{print out}输入;完成| awk'{a[$0]+}END{for(a中的i)print i,a[i]}排序
1 55
2 60
3 37
4 50
5 57
6 45
7 50
8 46
真正的0m1.924s
用户0.710s
系统0m0.932s
这似乎是大型输入文件的最佳解决方案:
awk -v seed="$RANDOM" -v max="$(wc -l < file)" 'BEGIN{srand(seed); n=int(rand()*max)+1} NR==n{print; exit}' file
因此,我们预先调用wc
和rand()
一次的解决方案比按预期为每一行调用rand()
要快。在bash shell上,首先将种子初始化为#line cube或您的选择
$ i=;while read a; do let i++;done<<<$var; let RANDOM=i*i*i
$ let l=$RANDOM%$i+1 ;echo -e $var |sed -En "$l p"
使用GNUsed
和bash
;nowc
或awk
将最后一个内部循环放入((c=0;c):
f=input-file
sed -n $((RANDOM%($(sed = $f | sed '2~2d' | sed -n '$p')) + 1))p $f
注意:$(…)
中的三个sed
是伪造wc-l
的低效方法。也许有更好的方法——当然,只使用sed
。使用shuf
:
$ echo "$var" | shuf -n 1
输出:
Hi
欢迎来到SO。Stack Overflow是一个面向专业和热情程序员的问答页面。请在问题中添加您自己的代码。您至少需要展示您自己为解决此问题所做的研究。谢谢,是的,没问题,我会编辑。已知的行数是多少?使用bash和sed执行此操作将非常简单效率更低,安装coreutils有什么问题?为什么需要专门使用sed?几乎每个系统上都有很多工具,可能更适合使用。我喜欢awk解决方案,我也同意,它似乎应该可以工作,但你不能调用rand()
在BEGIN部分中使用一次变量,而不是每行输入调用一次变量?因为srand()默认情况下使用当前秒数(从历元值算起)进行种子设定,如果在1秒内运行两次,它将生成相同的输出-如果您愿意,可以通过awk-v seed=“$RANDOM”BEGIN{srand(seed)更改该值“
对rand()
的后续调用将产生新的值…只有重新生成awk时才是一样的。但是你是对的!我们只需要调用一次!这将大大加快速度。这就是我所说的重新生成awk的情况。你不可能在1秒内调用两次,但如果调用了,你会得到相同的输出。”(除非你运气好,并且在大纪元改变后过了一秒)。就个人而言,我通常不想处理这个问题,但由于OP似乎非常关注随机性,我想我建议seed=“$RANDOM”
如果有问题的话。在BEGIN中只尝试调用rand一次,输出严重偏向文件的开头。不知道为什么…@EdMorton我没有。现在运行脚本计时。@Williampersell-您介意检查上面的内容并尝试计时,看看是否得到类似的结果吗?在我的笔记本电脑上,运行2次脚本(运行wc-l)实际上更快。每次只运行一次,12.864实时,vs 24.625。但我突然想到,我们可能错过了巨大内存的现代奇迹!对于这类事情,现在可能更容易将整个文件读入内存,然后在最后随机选择一行!
$ echo -e $var >varfile
$ i=;while read a; do let i++;done<varfile; let RANDOM=i*i*i
$ let l=$RANDOM%$i+1 ;sed -En "$l p" varfile
f=input-file
sed -n $((RANDOM%($(sed = $f | sed '2~2d' | sed -n '$p')) + 1))p $f
$ echo "$var" | shuf -n 1
Hi