如何从文件中删除随机行?

Pra*_*dam 7 command-line text-processing

我有一个包含 10000 行的文件,我想从中删除 5 个随机确定的行。我怎样才能做到这一点?

Byt*_*der 15

与需要每行处理整个文件一次才能删除的 for 循环相比,您可能可以更有效地解决它。

filename="/PATH/TO/FILE"
number=5

line_count="$(wc -l < "$filename")"
line_nums_to_delete="$(shuf -i "1-$line_count" -n "$number")"
sed_script="$(printf '%dd;' $line_nums_to_delete)"

sed -i.bak -e "$sed_script" "$filename"
Run Code Online (Sandbox Code Playgroud)

或者在一行中(在定义filenamenumber变量或手动替换它们之后):

sed -i.bak -e "$(printf '%dd;' $(shuf -i "1-$(wc -l < "$filename")" -n "$number"))" "$filename"
Run Code Online (Sandbox Code Playgroud)

-i.bak开关告诉sed编辑/立即更换输入文件,但保留原始数据,命名为喜欢的输入文件的备份副本,但与.bak附加到文件名。如果您不想复制它,只需编写-i.

顺便说一句,您不必像我一样使用变量。您也可以直接用适当的值替换"$number""$filename"。为了清楚起见,我只是这样做了。


分解并解释命令的其余部分:

sed -e "SCRIPT" "$filename"
Run Code Online (Sandbox Code Playgroud)

sedfilename变量指定的文件上运行文本处理工具,应用作为SCRIPT参数给出的指令。

我们SCRIPT在它上面的行中动态生成,它们运行命令并将它们的输出分配给变量。这里我们使用这些命令:

  • wc -l < "$filename"读入由filename变量指定的文件并输出该文件包含的行数。

    • 在您的情况下,根据您在问题中提到的大小,这应该返回大约 10000。
  • shuf -i "1-$line_count" -n "$number返回由number变量指定的数量在 1 到$line_count(包括两个边界)范围内的唯一随机数。

    • 例如,shuf -i 1-6 -n 2将模拟投掷两个常规六面骰子。
  • printf '%dd;' ARGUMENTS返回一个格式化的字符串,包含所有ARGUMENTS(这次不引用以将每个随机数视为单独的参数)。格式字符串%dd;将在剩余参数时重复,并将%d替换为表示为十进制数的参数。

    • 因此,例如输入1 7 42将导致输出1d;7d;42d;

结果最终$sed_script是我们的SCRIPTfor sed。普通数字被视为地址,即应用操作的行号,输入文件的第一行从 1 开始。d是删除指定行的命令,;分隔多个sed脚本命令。

总之,整个命令首先检查filename变量中指定的输入文件并计算其行数。然后它生成number许多在 1 到行数范围内的唯一随机数,并从中构建一个sed脚本来删除每个提到的随机行。最后sed在文件上运行该脚本,修改它。


Shi*_*tya 6

您可以使用 for 循环获取随机数并使用 sed 命令删除该行。

for i in {0..5};
 do sed -i "$((1 + RANDOM % 10000))d" filename; 
done
Run Code Online (Sandbox Code Playgroud)


小智 5

类似于 Shivaditya 的答案,但没有循环,并且会从整个文件中删除行而不仅仅是前 10 行:

sed -i "$((1+RANDOM%10000))d;$((1+RANDOM%10000))d;$((1+RANDOM%10000))d;$((1+RANDOM%10000))d;$((1+RANDOM%10000))d" filename
Run Code Online (Sandbox Code Playgroud)

将选择 1 到 10000 之间的五个随机数,并在一次操作中删除这些行。

  • 如果这些随机数中有两个或多个相同怎么办? (2认同)