首页 > 解决方案 > 删除空格分隔文本文件中某些索引处的条目

问题描述

我有一个 .txt 文件,其中包含某些“离群”数据点的数字索引,每个数据点都在自己的行上,由 $outlier_file 调用:

1 
7 
30 
43 
48 
49 
56 
57 
65 

使用以下代码,我可以通过使用 while + read 成功删除某些文件(在本例中为大量神经影像数据)。

while read outlier; do
    # Remove current outlier vol from eddy unwarped DWI data
    rm $DWI_path/$1/vol000*"$outlier".nii.gz;
done < $outlier_file

但是,我还需要从存储在 $bvec_file 中的另一个文本文件中删除位于这些“异常值”索引处的数字,该文件有 69 列和 3 行。在每一行中,数字以空格分隔。例如,对于这个例子,我需要删除第 1、7、30 等列的所有 3 行,然后将删除异常值的版本保存到一个新的 *.txt 文件中。

0  0.9988864166  -0.0415925034  -0.06652866169  -0.6187155495  0.2291534462  0.8892356214  0.7797364286  0.1957395685  0.9236669465  -0.5400265342  -0.3845263463  -0.4903989539  0.4863306385  -0.6496130843  0.5571164636  0.8110081715  0.9032142094  -0.3234596075  -0.1551409525  -0.806059879  0.4811597826  -0.7820757748  -0.9528881463  0.1916556621  -0.007136403284  -0.2459431735  -0.7915263574  -0.1938049261  -0.1578786349  0.8688043633  -0.5546072294  -0.4019951732  0.2806154851  0.3478762022  0.9548067252  -0.9696777541  -0.4816255837  -0.7962240023  0.6818610905  0.7097978218  0.6739686799  0.1317547111  -0.7648252249  -0.1456021218  -0.5948047487  0.0934205064  0.5268769564  -0.8618324858  -0.3721029232  -0.1827616535  0.691353613  0.4159071597  0.4605505287  0.1312199424  0.426674893  -0.4068291509  0.7167859082  0.2330824665  0.01909161256  -0.06375254731  -0.5981122948  -0.2672253674  0.6875472994  0.2302943724  0  0  0  0  
0  0.04258194557  0.9988207007  0.6287131425  0.7469024143  0.5528476637  0.3024964957  0.1446931241  0.9305823612  0.1675139932  0.8208211337  0.8238722992  0.5983722761  0.4238174961  0.639429196  0.1072148887  0.5551578885  0.003337599176  0.511740508  0.9516619405  0.3851404227  0.8526321065  0.1390947346  0.2030449535  0.7759459569  0.165587903  0.9523372297  0.5801228933  0.3277276562  0.7413928896  0.442482978  0.2320585706  0.1079269171  0.1868672655  0.1606136006  0.2968573235  0.1682337977  0.8745679247  0.5989061899  0.4172933119  0.01746934331  0.5641480832  0.7455469091  0.3471016571  0.8035001467  0.5870623128  0.361107261  0.8192579877  0.4160218909  0.5651330299  0.4070513153  0.7221181184  0.714223583  0.6971767133  0.4937978446  0.4232911691  0.8011701162  0.2870385494  0.9016941521  0.09688949547  0.9086826131  0.2631932421  0.152678096  0.6295753848  0.9712458578  0  0  0  0  
0  -0.02031513434  -0.02504539005  -0.7747862425  0.2435730944  0.8011542666  0.343155766  -0.6091592581  -0.3093581909  -0.3446424728  -0.1860752773  -0.4163819443  -0.6336083058  0.7641081337  -0.4112580017  -0.8234841915  0.1845683194  0.4291770641  -0.7959243273  -0.2650864686  0.449371034  -0.203724703  0.6074620459  0.2253373638  -0.6009791836  -0.9861692137  0.1804598471  0.1922068008  -0.9246806119  0.6522353256  -0.2222336438  0.7990992685  -0.9092588527  -0.9414539684  0.9236803664  0.0148272357  -0.1772637652  0.05628269894  -0.08566629406  -0.6007759525  0.7041888058  0.4769729119  0.6532997034  -0.5427364139  -0.5772239915  0.5491494803  0.9278330427  0.2263117816  -0.290121617  0.7363179158  0.8949343019  -0.02399176716  0.5629439653  -0.5493977074  -0.8596191107  -0.7992328333  0.4388809483  0.6354737076  0.3641705918  0.9951120218  0.412591228  -0.75696169  0.9514620339  -0.3618197699  0.06038199928  0  0  0  0  

据我所知,一种方法是使用 awk 来索引正确的列..(现在只是打印它们)但是如果我调用 $1 (即第一个异常值列的数字索引),我只能让它工作)...

awk -F ' ' '{print $1}' $bvec_file

如果我尝试引用 $outlier 中的值,它就不起作用。相反,这会打印 $bvec_file 的全部内容

while read outlier; do
    
    # Remove current outlier vol from eddy unwarped DWI data
    rm $DWI_path/$1/vol000*"$outlier".nii.gz;
    
    # Remove outlier #'s from bvec file 
    awk -F ' ' '{print $1}' $bvec_file

done < $outlier_file

我完全坚持如何完成这项工作。任何建议将不胜感激。

标签: bashshellawkwhile-loopsh

解决方案


要在循环后从 bvec_file 中删除异常值,并且仅删除成功删除关联文件的异常值:

#!/usr/bin/env bash

tmp=$(mktemp) || exit 1
while IFS= read -r outlier; do
    
    # Remove current outlier vol from eddy unwarped DWI data
    rm "$DWI_path/$1"/vol000*"$outlier".nii.gz &&
    echo "$outlier"

done < "$outlier_file" |
awk '
    NR==FNR { os[$0]; next }
    {
        for (o in os) {
            $o=""
        }
        $0=$0; $1=$1
    }
1' - "$bvec_file" > "$tmp" &&
mv "$tmp" "$bvec_file"

或者在删除文件时一次删除一个异常值:

#!/usr/bin/env bash

tmp=$(mktemp) || exit 1
while IFS= read -r outlier; do
    
    # Remove current outlier vol from eddy unwarped DWI data
    rm "$DWI_path/$1"/vol000*"$outlier".nii.gz &&
    
    # Remove outlier #'s from bvec file 
    awk -v o="$outlier" '{$o=""; $0=$0; $1=$1} 1' "$bvec_file" > "$tmp" &&
    mv "$tmp" "$bvec_file"

done < <(sort -rnu "$outlier_file")

始终引用您的 shell 变量,请参阅https://mywiki.wooledge.org/Quotes&&每行末尾的 是为了确保下一个命令仅在前面的命令成功时运行。

awk 脚本中的神奇咒语执行以下操作 - 假设您的输入是a b c并且异常值字段是字段编号 2 b,:

$ echo 'a b c'
a b c
$
$ echo 'a b c' | awk -v o=2 '{$o=""; print NF ":", $0}'
3: a  c
$
$ echo 'a b c' | awk -v o=2 '{$o=""; $0=$0; print NF ":", $0}'
2: a  c
$
$ echo 'a b c' | awk -v o=2 '{$o=""; $0=$0; $1=$1; print NF ":", $0}'
2: a c

o=""字段值设置为 null,$0=$0强制 awk 重新拆分$0为字段,因此它有效地删除字段 2(与将其设置为 null 但它仍然存在的上一步相反),并且从它的字段中$1=$1重新组合$0替换每个FS(任何连续的空白字符链,包括现在ac)之间的 2 个空格和OFS(单个空白字符)。


推荐阅读