Contents

从Linux中的文件中读取随机行

1. 概述

在本教程中,我们将研究从文件中随机选择一行文本的不同策略。

2. 创建我们的示例文件

在我们开始之前,让我们创建一个名为example_file.txt的文件,其中将包含 10 行编号:

$ : > example_file.txt; seq 1 10 | xargs -I % echo line % | tee -a example_file.txt

3.使用shuf

首先,让我们看一下shuf 命令。在这种情况下,我们提供我们想要的行数,shuf将返回一个随机行:

$ shuf -n 1 example_file.txt
line 2

4. 使用awk

解决该问题的另一种方法是使用awk

第一种方法是当我们知道文件中的行数时:

$ n_lines=$(wc -l < example_file.txt); awk -v min=1 -v max=$n_lines '
BEGIN {
    srand()
    r_number=int( min + rand() * (max - min + 1) )
} 
NR == r_number' example_file.txt

现在让我们仔细看看代码:

  • 使用*n_lines=$(wc -l < example_file.txt),*我们从文件中获取行数
  • 使用*-v min=1 -v max=$n_lines*,我们将获取随机数的范围信息传递给awk脚本
  • 在这里,在:*r_number=int( min + rand() * (max – min + 1) )*中,我们从使用传递的变量构建的范围中获取随机数
  • 使用NR == r_number,我们指示awk如果当前注册表的编号与之前创建的随机数相同,则执行默认的awk操作:打印当前行

当我们不知道文件中的行数或者我们只想在没有任何其他命令帮助的情况下使用awk时,第二种方法很有用:

$ awk '
BEGIN{ srand() } 
rand() * NR < 1 { 
    line = $0 
} 
END { print line }' example_file.txt

使用srand函数,我们使用当前日期和时间作为生成随机数的种子。出于这个原因,如果我们在短时间内多次运行我们的命令,我们将得到相同的行

5. 使用perl

我们也可以使用 Perl 创建一个类似于awk策略的脚本:

$ perl -e 'srand; rand($.) < 1 && ( $line = $_ ) while <>; print $line' example_file.txt

6. 使用sed

现在,让我们使用sed 命令:

$ rnd=$(( 1 + $RANDOM % $(wc -l < example_file.txt) )); sed -n "${rnd}p" example_file.txt

让我们仔细看看最后的命令行:

  • *在rnd=$(( 1 + $RANDOM % $(wc -l < example_file.txt) ))*部分,我们选择一个从 1 到文件行数范围内的随机数
  • 在sed -n “${rnd}p” example_file.txt部分,我们指示sed打印其编号等于先前获得的随机数的行

由于bashzsh具有内部变量RANDOM和模运算符,我们能够实现这一点。

7. 利用 Bash 和 Zsh 的能力

虽然仅使用bashzsh创建策略不是最好的主意,因为它会很不清晰且不太便携,但从教学的角度来看它很有趣。 我们将仅使用bashzsh的内置命令和内部变量来实现我们的每一种方法。

如果我们知道文件中的行数:

$ n_lines=0
while read l
do 
    ((++n_lines))
done < example_file.txt
rnd_line=$(( 1 + RANDOM % n_lines))
n_line=1
while read line
do 
    (( n_line == rnd_line )) && break
    ((n_line++))
done < example_file.txt
echo "$line"

否则,让我们依靠我们对perlawk所做的事情:

$ n_line=1
while read crt_line
do 
    (( RANDOM % n_line < 1 )) && line="$crt_line"
    ((++n_line))
done < example_file.txt
echo "$line"

除了在命令行上运行代码外,我们还可以将其保存到一个文件中以作为可执行文件运行。