我想随机调整文本文件的行并创建一个新文件。该文件可能有数千行。
我怎样才能做到这一点与cat
,awk
,cut
等?
我想随机调整文本文件的行并创建一个新文件。该文件可能有数千行。
我怎样才能做到这一点与cat
,awk
,cut
等?
Answers:
您可以使用shuf
。至少在某些系统上(似乎不在POSIX中)。
正如jleedev指出的那样:sort -R
也可能是一个选择。至少在某些系统上;好吧,你知道了。有人指出,这sort -R
并不是真正的洗牌,而是根据其哈希值对项目进行排序。
[编者注:除了重复的行/排序键总是彼此相邻结束之外,sort -R
几乎都改组了。换句话说:只有使用唯一的输入行/键,它才是真正的随机播放。确实,输出顺序是由哈希值决定的,但随机性来自选择随机哈希函数 -参见手册。
shuf
并sort -R
略有不同,因为sort -R
根据元素的哈希值对元素进行随机排序,也就是说,sort -R
会将重复的元素放在一起,而shuf
将所有元素随机洗牌。
brew install coreutils
,然后使用gshuf ...
(:
sort -R
并且shuf
应该被视为完全不同。sort -R
是确定性的。如果您在相同的输入上在不同的时间两次调用它,您将得到相同的答案。shuf
另一方面,会产生随机输出,因此很可能会在同一输入上提供不同的输出。
Perl单线将是Maxim解决方案的简单版本
perl -MList::Util=shuffle -e 'print shuffle(<STDIN>);' < myfile
\n
;是的,\n
必须存在-通常是 -否则您将得到您所描述的内容。
<STDIN>
为<>
,因此该解决方案也适用于文件输入。
该答案通过以下方式补充了许多现有的出色答案:
现有答案被打包到灵活的shell函数中:
stdin
输入,还接受文件名参数SIGPIPE
通常的方式处理(使用退出代码安静终止141
),而不是吵闹。在将功能输出管道输送到较早关闭的管道时(例如管道输送到),这一点很重要head
。进行性能比较。
awk
,sort
以及cut
改编自OP自己的答案:shuf() { awk 'BEGIN {srand(); OFMT="%.17f"} {print rand(), $0}' "$@" |
sort -k1,1n | cut -d ' ' -f2-; }
shuf() { perl -MList::Util=shuffle -e 'print shuffle(<>);' "$@"; }
shuf() { python -c '
import sys, random, fileinput; from signal import signal, SIGPIPE, SIG_DFL;
signal(SIGPIPE, SIG_DFL); lines=[line for line in fileinput.input()];
random.shuffle(lines); sys.stdout.write("".join(lines))
' "$@"; }
有关此功能的Windows版本,请参见底部。
shuf() { ruby -e 'Signal.trap("SIGPIPE", "SYSTEM_DEFAULT");
puts ARGF.readlines.shuffle' "$@"; }
性能比较:
注意:这些数字是在2012年末配备3.2 GHz Intel Core i5和运行OSX 10.10.3的Fusion Drive的iMac上获得的。尽管时间会随所使用的OS,机器规格和awk
所使用的实现而变化(例如,awk
OSX上使用的BSD 版本通常比GNU慢awk
,尤其是mawk
),但这应该提供相对性能的一般含义。
输入文件是一个1百万行文件与产生seq -f 'line %.0f' 1000000
。
时间以升序排列(最快的是第一个):
shuf
0.090s
0.289s
0.589s
1.342s
使用Python 2.7.6; 2.407s
(!)使用Python 3.4.2awk
+ sort
+cut
3.003s
与BSD awk
; 2.388s
使用GNU awk
(4.1.1); 1.811s
与mawk
(1.3.4);为了进一步比较,上述未打包为功能的解决方案:
sort -R
(如果输入行重复,则不是真正的随机播放)
10.661s
-分配更多的内存似乎没有什么不同24.229s
bash
循环+ sort
32.593s
结论:
shuf
如果可以,请使用 -这是迄今为止最快的。awk
+ sort
+ cut
组合用作不得已的方法 ; awk
您使用哪种实现很重要(mawk
比GNU快awk
,而BSD awk
最慢)。sort -R
,bash
循环和Scala。Windows版本的Python解决方案(除了引号和与信号相关的语句的删除(Windows不支持)之外,Python代码是相同的):
$OutputEncoding
如果要通过管道发送非ASCII字符,则必须进行调整):# Call as `shuf someFile.txt` or `Get-Content someFile.txt | shuf`
function shuf {
$Input | python -c @'
import sys, random, fileinput;
lines=[line for line in fileinput.input()];
random.shuffle(lines); sys.stdout.write(''.join(lines))
'@ $args
}
请注意,PowerShell可以通过其Get-Random
cmdlet在本地进行改组(尽管性能可能会成为问题);例如:
Get-Content someFile.txt | Get-Random -Count ([int]::MaxValue)
cmd.exe
(批处理文件):保存到文件shuf.cmd
,例如:
@echo off
python -c "import sys, random, fileinput; lines=[line for line in fileinput.input()]; random.shuffle(lines); sys.stdout.write(''.join(lines))" %*
python -c "import sys, random; lines = [x for x in sys.stdin.read().splitlines()] ; random.shuffle(lines); print(\"\n\".join([line for line in lines]));"
from signal import signal, SIGPIPE, SIG_DFL; signal(SIGPIPE, SIG_DFL);
原始解决方案就足够了,并且保留了能够传递文件名参数的灵活性-无需更改其他任何内容(除了引号)-请参阅我在底部。
我使用了一个很小的perl脚本,我称之为“ unsort”:
#!/usr/bin/perl
use List::Util 'shuffle';
@list = <STDIN>;
print shuffle(@list);
我也有一个以NULL分隔的版本,称为“ unsort0” ...方便与find -print0等一起使用。
PS:也投票赞成“ shuf”,我不知道这些天在coreutils中有没有……如果您的系统没有“ shuf”,则上面的内容可能仍然有用。
<STDIN>
为<>
,以使解决方案也可以使用文件中的输入。
这是第一次尝试,在编码器上很容易,但是在CPU上却很困难,它将随机数添加到每行,对它们进行排序,然后从每行中剥离随机数。实际上,这些行是随机排序的:
cat myfile | awk 'BEGIN{srand();}{print rand()"\t"$0}' | sort -k1 -n | cut -f2- > myfile.shuffled
head myfile | awk ...
。然后我将其更改为cat;这就是为什么它留在那里的原因。
-k1 -n
排序,因为awk的输出rand()
是介于0和1之间的小数,并且所有重要的是它以某种方式被重新排序。-k1
尽管rand()的输出应该足够唯一以使比较短路,但它可能会通过忽略其余部分来帮助加快速度。
cat filename |
(或< filename |
)比记住每个程序如何(或不)获取文件输入要好。
这是一个awk脚本
awk 'BEGIN{srand() }
{ lines[++d]=$0 }
END{
while (1){
if (e==d) {break}
RANDOM = int(1 + rand() * d)
if ( RANDOM in lines ){
print lines[RANDOM]
delete lines[RANDOM]
++e
}
}
}' file
输出
$ cat file
1
2
3
4
5
6
7
8
9
10
$ ./shell.sh
7
5
10
9
6
8
2
1
3
4
python的一线式:
python -c "import random, sys; lines = open(sys.argv[1]).readlines(); random.shuffle(lines); print ''.join(lines)," myFile
对于仅打印一条随机行:
python -c "import random, sys; print random.choice(open(sys.argv[1]).readlines())," myFile
但是请参阅这篇文章以了解python的缺点random.shuffle()
。它不适用于许多(超过2080个)元素。
/dev/urandom
。若要从Python的使用它:random.SystemRandom().shuffle(L)
。
.readLines()
返回带有尾随换行符的行。
简单的基于awk的函数将完成此任务:
shuffle() {
awk 'BEGIN{srand();} {printf "%06d %s\n", rand()*1000000, $0;}' | sort -n | cut -c8-
}
用法:
any_command | shuffle
这在几乎所有的UNIX上都可以使用。在Linux,Solaris和HP-UX上进行了测试。
更新:
请注意,前导零(%06d
)和rand()
乘法使得它也可以在sort
不理解数字的系统上正常工作。可以通过字典顺序对其进行排序(也称为普通字符串比较)。
"$@"
,它也可以作为输入使用文件。没有理由乘以rand()
,因为sort -n
它可以对小数点排序。但是,控制awk
输出格式是个好主意,因为使用默认格式时%.6g
,rand()
将以指数形式输出偶数。在实践中,改组多达100万条线路可以说是足够的,但是在不付出很多性能损失的情况下,轻松支持更多线路是很容易的。例如%.17f
。
sort
应该能够处理小数部分(即使有数千个分隔符,正如我刚刚注意到的那样)。
这是我作为rand.py保存在主文件夹中的python脚本:
#!/bin/python
import sys
import random
if __name__ == '__main__':
with open(sys.argv[1], 'r') as f:
flist = f.readlines()
random.shuffle(flist)
for line in flist:
print line.strip()
在Mac OSX上sort -R
和shuf
不可用,所以你可以在你的.bash_profile作为别名此:
alias shuf='python rand.py'
如果像我一样,您是来这里寻找shuf
macOS 的替代产品,然后使用randomize-lines
。
安装randomize-lines
(自制程序)软件包,该软件包rl
具有与相似的功能的命令shuf
。
brew install randomize-lines
Usage: rl [OPTION]... [FILE]...
Randomize the lines of a file (or stdin).
-c, --count=N select N lines from the file
-r, --reselect lines may be selected multiple times
-o, --output=FILE
send output to file
-d, --delimiter=DELIM
specify line delimiter (one character)
-0, --null set line delimiter to null character
(useful with find -print0)
-n, --line-number
print line number with output lines
-q, --quiet, --silent
do not output any errors or warnings
-h, --help display this help and exit
-V, --version output version information and exit
brew install coreutils
提供的shuf
二进制文件为gshuf
。
这个bash函数具有最小的依赖性(仅sort和bash):
shuf() {
while read -r x;do
echo $RANDOM$'\x1f'$x
done | sort |
while IFS=$'\x1f' read -r x y;do
echo $y
done
}
awk
辅助解决方案相似,但是对于较大的输入,性能将是一个问题;您对单个$RANDOM
值的使用最多只能正确混洗多达32,768条输入行;尽管可以扩展该范围,但可能不值得:例如,在我的机器上,在32,768条短输入行上运行脚本大约需要1秒,这是运行shuf
时间的150倍 ,大约10-15倍只要OP自己的awk
辅助解决方案即可。如果您可以依靠sort
在场,awk
那么也应该在那里。
在Windows中,您可以尝试使用此批处理文件来帮助您重新整理data.txt,批处理代码的用法是
C:\> type list.txt | shuffle.bat > maclist_temp.txt
发出此命令后,maclist_temp.txt将包含随机的行列表。
希望这可以帮助。
截至目前尚未提及:
该unsort
UTIL。语法(某种程度上面向播放列表):
unsort [-hvrpncmMsz0l] [--help] [--version] [--random] [--heuristic]
[--identity] [--filenames[=profile]] [--separator sep] [--concatenate]
[--merge] [--merge-random] [--seed integer] [--zero-terminated] [--null]
[--linefeed] [file ...]
msort
可以按行随机播放,但这通常是过大的:
seq 10 | msort -jq -b -l -n 1 -c r