删除 txt 文件中第二列标记为 0 的 50 个随机行

删除 txt 文件中第二列标记为 0 的 50 个随机行

我想使用终端命令从一个 txt 文件中删除 50 个随机行,该文件以制表符分隔,并包含这些示例行,其中第二列为 0。第二列中的值是 0 或 1。这是一个没有标题的 txt 文件。我该怎么做?

TCGA-05-4244-01 0   TCGA-05-4244-01A-01-TS1
TCGA-05-4249-01 0   TCGA-05-4249-01A-01-TS1
TCGA-05-4250-01 0   TCGA-05-4250-01A-01-TS1
TCGA-05-4382-01 1   TCGA-05-4382-01A-01-TS1
TCGA-05-4384-01 0   TCGA-05-4384-01A-01-TS1
TCGA-05-4389-01 0   TCGA-05-4389-01A-01-TS1
TCGA-05-4390-01 0   TCGA-05-4390-01A-01-TS1
TCGA-05-4395-01 0   TCGA-05-4395-01A-01-TS1
TCGA-05-4397-01 0   TCGA-05-4397-01A-01-TS1

答案1

尝试awk

awk '
  NR==FNR {lines[$0]++;next}
  (not FNR in lines)
' <(awk -F '\t' '$2==0{print NR}' file.txt | shuf -n 50) file.txt
  • awk -F '\t' '$2==0{print NR}' file.txt | shuf -n 50将随机选择 50 行$2==0进行删除。
  • NR==FNR {lines[$0]++;next}将获得这些行号作为数组lines-(要删除)。
  • (not FNR in lines)将获取不在 lines-to-delete 变量中的行并执行默认操作 (= print)。

答案2

您可以使用这个 Bash 脚本:

#!/bin/bash

i=1
nlines=$(wc -l < "$1")

while [[ $i -le 50 ]]; do
    row=$((1 + $RANDOM % nlines))
    num=$(sed -n "${row}p" "$1" | cut -f 2)

    if [[ $num -eq 0 ]]; then
        sed -i "${row}d" "$1"
        ((nlines--))
        ((i++))
    fi
done

将其保存到.sh具有您选择的名称的文件中(我myscript.sh在这里使用该名称)并通过运行使其可执行:

chmod u+x myscript.sh

然后按如下方式使用它来0随机删除名为 的文件的第二列中包含的 50 行file.txt

myscript.sh /path/to/your/file.txt

笔记

  • 首先在样本数据中测试脚本,以确保其按预期工作。请勿将其用于研究数据,因为它们将被永久更改!

  • 脚本会将更改保存到您用作参数 ( file.txt) 的同一文件中。请务必保留原始数据的副本!

  • 该脚本不会检查空行,因此请确保数据中没有空行。

答案3

如果您只想删除 50 个随机行,请获取 1 到文件中行数之间的 50 个随机数列表,然后从文件中删除这些行。例如:

## store the number of lines in the file in the variable $lines
lines=$(wc -l < file)

## Get 50 random numbers from 1 to $lines and print to the file lineNums
seq 1 $lines | shuf -n 50 > lineNums

## Use awk to print except if the current line number is in lineNums
awk 'NR==FNR{lines[$0]++; next} (FNR in lines){next}1' lineNums file >  newfile

答案4

由于字段 2 中的值始终为01,因此您可以使用gawk仅打印第二个字段为 的行1。这在功能上等效于删除第二个字段为 的行0

gawk '$2==1' file.txt

如果该输出看起来正确,则可以使用以下选项用此输出替换文件的内容-i inplace

gawk -i inplace '$2==1' file.txt

编辑

另一方面,如果目的是随机删除其中 50 行的第二列为零,类似下面的方法可以实现:

for n in $(shuf -en50 $(awk '$2==0{print FNR}' file.txt) | sort -gr); do
    sed -i "${n}"d file.txt
done

或者用一行代码来表达:

for n in $(shuf -en50 $(awk '$2==0{print FNR}' file.txt)|sort -gr); do sed -i "${n}"d file.txt; done

从内向外扩展:

awk '$2==0{print FNR}' file.txt打印字段 2file.txt中的所有行的行号。0

shuf -en50随机打乱行号列表然后打印其中 50 个(假设结果中至少有 50 行awk)。

sort -gr对具有最高数字的 50 行进行反向排序(g即按数字排序而不是默认的字典排序)(我们将按照相同的顺序从文件中删除这些行)。

循环for处理这个数字列表,在每次迭代时将变量分配n给列表项,然后执行sed -i "${n}"d file.txt从中删除该行号file.txt

相关内容