在随机化之前根据先前的文件顺序重新排序行

Dom*_*red 0 linux bash awk grep sed

我有以下几行file1:

line 1text
line 2text
line 3text
line 4text
line 5text
line 6text
line 7text
Run Code Online (Sandbox Code Playgroud)

通过命令,cat file1 | sort -R | head -4我得到以下内容file2:

line 5text
line 1text
line 7text
line 2text
Run Code Online (Sandbox Code Playgroud)

我想在下面命名行(不是数字,只是相同的顺序file1)file3:

line 1text
line 2text
line 5text
line 7text
Run Code Online (Sandbox Code Playgroud)

实际数据没有数字.有什么简单的方法吗?我正在考虑做一个grep并在循环中找到第一个实例.但是,我相信你经验丰富的人知道一个更简单的解决方案.您的积极意见得到高度赞赏.

Ben*_* W. 5

您可以使用行号进行装饰,选择四行随机行,按行号排序并删除行号:

$ nl -b a file1 | shuf -n 4 | sort -n -k 1,1 | cut -f 2-
line 2text
line 5text
line 6text
line 7text
Run Code Online (Sandbox Code Playgroud)

-b a以选项nl可以确保还空行进行编号.

请注意,这会将所有内容加载file1到内存中,如ghoti所指出的那样.为了避免这种情况(以及通常更智能的解决方案),我们可以使用(GNU)的不同功能shuf:它的-i选项采用数字范围并将每个数字视为一条线.要从输入文件中获取四个随机行号file1,我们可以使用

shuf -n 4 -i 1-$(wc -l < file1)
Run Code Online (Sandbox Code Playgroud)

现在,我们必须准确打印这些行.Sed可以做到这一点; 我们只需将上一个命令的输出转换为sed脚本并运行sed sed -n -f -.全部一起:

shuf -n 4 -i 1-$(wc -l < file1) | sort -n | sed 's/$/p/;$s/p/{&;q}/' |
    sed -n -f - file1
Run Code Online (Sandbox Code Playgroud)
  • sort -n用数字排序行号.这不是严格要求的,但是如果我们知道最后一行的最后一行,我们可以在之后退出sed,而不是一无所获地读取文件的其余部分.
  • sed 's/$/p/;$s/p/{&;q}/附加p到每一行.对于最后一行,我们追加{p;q}停止处理该文件.

    如果输出sort看起来像

    27
    774
    670
    541
    
    Run Code Online (Sandbox Code Playgroud)

    然后sed命令将其转换为

    27p
    774p
    670p
    541{p;q}
    
    Run Code Online (Sandbox Code Playgroud)
  • sed -n -f - file1进程file1,使用上面的sed命令的输出作为sed的说明.-n抑制我们不想要的行的输出.

该命令可以参数化并放入shell函数中,将文件名和行数作为参数打印:

randlines () {
    fname=$1
    nlines=$2

    shuf -n "$nlines" -i 1-$(wc -l < "$fname") | sort -n |
        sed 's/$/p/;$s/p/{&;q}/' | sed -n -f - "$fname"
}
Run Code Online (Sandbox Code Playgroud)

用得像

randlines file1 4
Run Code Online (Sandbox Code Playgroud)