如何从shell中的文本文件中选择随机唯一行?

时间:2012-04-12 06:47:47

标签: shell sed awk

我有一个行数未知的文本文件。我需要随机抓取其中的一些行,但我不希望有任何重复的风险。

我试过了:

jot -r 3 1 `wc -l<input.txt` | while read n; do
  awk -v n=$n 'NR==n' input.txt
done

但这很难看,并且不能防止重复。

我也试过这个:

awk -vmax=3 'rand() > 0.5 {print;count++} count>max {exit}' input.txt

但这显然也不是正确的方法,因为我甚至无法保证获得max行。

我被困住了。我该怎么做?

7 个答案:

答案 0 :(得分:4)

如果您可以访问Python(将10更改为您想要的内容):

python -c 'import random, sys; print("".join(random.sample(sys.stdin.readlines(), 10)).rstrip("\n"))' < input.txt

(这将在Python 2.x和3.x中使用。)

另外,(再次将10更改为适当的值):

sort -R input.txt | head -10

答案 1 :(得分:4)

这可能对您有用:

shuf -n3 file

shuf是GNU coreutils之一。

答案 2 :(得分:2)

如果你的系统上有jot,那么我猜你运行的是FreeBSD或OSX而不是Linux,所以你可能没有rlsort -R这样的工具。

不用担心。我不得不这么做。试试这个:

[ghoti@pc ~]$ cat rndlines
#!/bin/sh

# default to 3 lines of output
lines="${1:-3}"

# First, put a random number at the begginning of each line.
while read line; do
  echo "`jot -r 1 1 1000000` $line"
done < input.txt > stage1.txt

# Next, sort by the random number.
sort -n stage1.txt > stage2.txt

# Last, remove the number from the start of each line.
sed -r 's/^[0-9]+ //' stage2.txt > stage3.txt

# Show our output
head -n "$lines" stage3.txt

# Clean up
rm stage1.txt stage2.txt stage3.txt

[ghoti@pc ~]$ ./rndlines input.txt 
two
one
five
[ghoti@pc ~]$ ./rndlines input.txt 
four
two
three
[ghoti@pc ~]$

我的input.txt有五行,带有指定的数字。

我已经拼出了这个以便于阅读,但在现实生活中,你可以将东西组合成长管道,并且你想要清理你可能创建的任何(唯一命名的)临时文件。

这是一个单行示例,使用awk也可以更加干净地插入随机数:

$ printf 'one\ntwo\nthree\nfour\nfive\n' | awk 'BEGIN{srand()} {printf("%.20f %s\n", rand(), $0)}' | sort | head -n 3 | cut -d\  -f2-

请注意,旧版本的sed(在FreeBSD和OSX中)可能需要-E选项而不是-r来代替ERE或正则表达式中的BRE方言。 (当然,您可以在BRE中表达这一点,但为什么?)(sed的古老版本(HP / UX等)可能需要BRE,但如果您已经知道如何执行此操作,那么您只会使用它们。)

答案 3 :(得分:2)

这应该可以解决问题,至少使用bash并假设您的环境中有其他命令可用:

cat chk.c | while read x; do
    echo $RANDOM:$x
done | sort -t: -k1 -n | tail -10 | sed 's/^[0-9]*://'

它基本上输出你的文件,在每行的开头放一个随机数。

然后它对该数字进行排序,抓取最后10行,并从中删除该数字。

因此,它会从文件中提供10个随机行,没有重复。

例如,以下是该chk.c文件运行三次的记录:

====
pax$ testprog chk.c
} else {
}
newNode->next = NULL;
colm++;

====
pax$ testprog chk.c
}

arg++;
printf (" [%s] n", currNode->value);
free (tempNode->value);

====
pax$ testprog chk.c

char tagBuff[101];
}
return ERR_OTHER;
#define ERR_MEM 1

===
pax$ _

答案 4 :(得分:2)

sort -Ru filename | head -5

将确保没有重复。并非sort的所有实施都具有-R选项。

答案 5 :(得分:1)

使用Perl从N获取FILE个随机行:

perl -MList::Util=shuffle -e 'print shuffle <>' FILE | head -N

答案 6 :(得分:1)

如果您不想安装任何其他内容,请使用ruby:

cat filename | ruby -e 'puts ARGF.read.split("\n").uniq.shuffle.join("\n")' 

例如,给定一个看起来像的文件(dups.txt):

1 2
1 3
2
1 2
3
4
1 3
5
6
6
7

您可能会得到以下输出(或某些排列):

cat dups.txt| ruby -e 'puts ARGF.read.split("\n").uniq.shuffle.join("\n")'
4
6
5
1 2
2
3
7
1 3

评论中的进一步示例:

printf 'test\ntest1\ntest2\n' | ruby -e 'puts ARGF.read.split("\n").uniq.shuffle.join("\n")'
test1
test
test2

当然,如果你有一个重复测试行的文件,你只会得到一行:

printf 'test\ntest\ntest\n' | ruby -e 'puts ARGF.read.split("\n").uniq.shuffle.join("\n")'
test