一个过滤条件,两个文件
one filter criteria, two files
我有一个看起来像这样的文件
VAR1 VAR2 VAR3 VAR4
ID1 foo 0.1 0.1
ID2 foo 1 1
ID3 foo foo .
ID4 foo foo foo
ID5 foo . 1
ID6 foo -0.1 -0.1
ID7 foo -1 -1
ID8 foo 5e-08 5e-08
我想根据一组连续的标准过滤掉行(例如,首先从第 3 列中删除所有 non-numeric 条目,然后从第 4 列中删除所有否定条目)但我想保存满足这些条件的所有行中间标准。也就是说,我的最终输出应该是 1) 一个包含在第一步中删除的所有行的文件,2) 一个包含在下一步中删除的所有行的文件,以及 3) 一个包含过滤后所有行的文件.
到目前为止我得到的是:
awk '!=*1 {print}' < file.txt > REMOVED_COL_3.txt
if [[ $( find REMOVED_COL_3.txt -type f -size +0c 2>/dev/null ) ]]
then
awk '==*1' < file.txt > tmp.txt && mv tmp.txt file.txt
fi
awk '<0 {print}' < file.txt > REMOVED_COL_4.txt
if [[ $( find REMOVED_COL_4.txt -type f -size +0c 2>/dev/null ) ]]
then
awk '>=0 {print}' < file.txt > tmp.txt && mv tmp.txt file.txt
fi
这行得通,但在我的真实数据集中花费了很多时间(预过滤了约 1300 万行)。
是否可以 awk
一次,将符合条件的行保存在一个文件中,不符合条件的行保存在另一个文件中?还是别的?
编辑:
我忘记了文件中的 header
这在单个 awk 脚本中是很有可能的。您可以在 awk
中使用 if/else if/else
以及将您的个人 print
语句重定向到不同的文件:
awk '{ if (!=*1) {print [=10=] > "REMOVED_COL_3.txt"} else if (<0) {print [=10=] > "REMOVED_COL_4.txt"} else {print [=10=] > "everythingelse_out.txt"}}' file.txt && mv -f everythingelse_out.txt file.txt
awk '
NR==1 {
split("REMOVED_COL_3.txt REMOVED_COL_4.txt tmp.txt",outfiles)
for (outnr in outfiles) {
print > outfiles[outnr]
}
next
}
{
if ( != +0) { outnr=1 }
else if ( < 0) { outnr=2 }
else { outnr=3 }
print > outfiles[outnr]
}
' file.txt &&
mv tmp.txt file.txt
我使用 +0
而不是 *1
将字符串转换为数字,因为加法通常比乘法快一点,而且这是执行该操作的更常见方式,请参阅 https://www.gnu.org/software/gawk/manual/gawk.html#Conversion: To force a string to be converted to a number, add zero to that string.
我有一个看起来像这样的文件
VAR1 VAR2 VAR3 VAR4
ID1 foo 0.1 0.1
ID2 foo 1 1
ID3 foo foo .
ID4 foo foo foo
ID5 foo . 1
ID6 foo -0.1 -0.1
ID7 foo -1 -1
ID8 foo 5e-08 5e-08
我想根据一组连续的标准过滤掉行(例如,首先从第 3 列中删除所有 non-numeric 条目,然后从第 4 列中删除所有否定条目)但我想保存满足这些条件的所有行中间标准。也就是说,我的最终输出应该是 1) 一个包含在第一步中删除的所有行的文件,2) 一个包含在下一步中删除的所有行的文件,以及 3) 一个包含过滤后所有行的文件.
到目前为止我得到的是:
awk '!=*1 {print}' < file.txt > REMOVED_COL_3.txt
if [[ $( find REMOVED_COL_3.txt -type f -size +0c 2>/dev/null ) ]]
then
awk '==*1' < file.txt > tmp.txt && mv tmp.txt file.txt
fi
awk '<0 {print}' < file.txt > REMOVED_COL_4.txt
if [[ $( find REMOVED_COL_4.txt -type f -size +0c 2>/dev/null ) ]]
then
awk '>=0 {print}' < file.txt > tmp.txt && mv tmp.txt file.txt
fi
这行得通,但在我的真实数据集中花费了很多时间(预过滤了约 1300 万行)。
是否可以 awk
一次,将符合条件的行保存在一个文件中,不符合条件的行保存在另一个文件中?还是别的?
编辑: 我忘记了文件中的 header
这在单个 awk 脚本中是很有可能的。您可以在 awk
中使用 if/else if/else
以及将您的个人 print
语句重定向到不同的文件:
awk '{ if (!=*1) {print [=10=] > "REMOVED_COL_3.txt"} else if (<0) {print [=10=] > "REMOVED_COL_4.txt"} else {print [=10=] > "everythingelse_out.txt"}}' file.txt && mv -f everythingelse_out.txt file.txt
awk '
NR==1 {
split("REMOVED_COL_3.txt REMOVED_COL_4.txt tmp.txt",outfiles)
for (outnr in outfiles) {
print > outfiles[outnr]
}
next
}
{
if ( != +0) { outnr=1 }
else if ( < 0) { outnr=2 }
else { outnr=3 }
print > outfiles[outnr]
}
' file.txt &&
mv tmp.txt file.txt
我使用 +0
而不是 *1
将字符串转换为数字,因为加法通常比乘法快一点,而且这是执行该操作的更常见方式,请参阅 https://www.gnu.org/software/gawk/manual/gawk.html#Conversion: To force a string to be converted to a number, add zero to that string.