我想使用终端命令从一个 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 中的值始终为0
或1
,因此您可以使用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
。