一个过滤条件,两个文件

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.