Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用shell删除特定列中包含特定字符串的50%行_Shell - Fatal编程技术网

使用shell删除特定列中包含特定字符串的50%行

使用shell删除特定列中包含特定字符串的50%行,shell,Shell,我有一个数据文件,它有许多行和列。我想随机删除第二列中包含数字“2”的50%的行。如何在shell脚本中执行此操作?我的文件如下所示: 264 2 -1.2000000000000000e+00 7.0825130926872939e+00 9.5601084339752944e+00 7.2651799153974066e+00 245 4 2.3999999999999999e+00 3.2314933672268427e+00 8.1060222635488888e+00 4.93009

我有一个数据文件,它有许多行和列。我想随机删除第二列中包含数字“2”的50%的行。如何在shell脚本中执行此操作?我的文件如下所示:

264 2 -1.2000000000000000e+00 7.0825130926872939e+00 9.5601084339752944e+00 7.2651799153974066e+00 
245 4 2.3999999999999999e+00 3.2314933672268427e+00 8.1060222635488888e+00 4.9300995049182887e+00
602 2 2.3999999999999999e+00 7.9943142143951045e+00 8.9555257846190486e+00 6.1149829552712900e+00 
323 3 -1.2000000000000000e+00 9.5688081384508621e+00 1.0611671606914694e+01 8.9952891594417164e+00 
45 3 -1.2000000000000000e+00 9.4185463105240714e+00 9.3227605688201560e+00 6.6654941991009027e+00  
103 2 2.3999999999999999e+00 1.0178713184773681e+01 1.0522860587449216e+01 7.5396990175229996e+00 
462 2 2.3999999999999999e+00 4.2166316392533885e+00 6.9152554630316221e+00 7.5523911902369765e+00 
239 3 -1.2000000000000000e+00 7.8204053112970211e+00 8.2536094294868985e+00 9.4685060963111152e+00 
598 3 -1.2000000000000000e+00 7.9895230606907504e+00 7.3376809962958367e+00 6.1930783591087541e+00 

假设您的数据位于名为
input
的文件中:

awk 'BEGIN{srand()} $2!=2 || int(2*rand()) {print}' input
说明:

  • 开始{srand()}

    这将为随机数生成器选择一个随机种子。这在
    awk
    开始循环文件的每一行之前完成一次

  • 2美元=2 | | int(2*rand()){print}

    awk
    中,这是一个带有条件的语句。语句是
    print
    ,它将打印当前行的全部内容,但仅当条件为真时。条件有两个部分,它们是or-d。如果第二列的值不是2:
    $2,则该条件为true=2
    。或者,如果
    int(2*rand())
    的计算结果为非零(随机发生的概率为50-50),则为真

    因此,第二列等于2的行中大约有一半被随机删除

正好得到一半 如果一个人以50-50的几率保留
$2==2
行,他就不会保留50%,就像掷一枚公平的硬币不会给出50%的正面一样。假设受影响的行数为偶数,则以下代码将补偿该保留,精确到50%:

awk 'BEGIN{srand()}
     NR==FNR && $2==2 {a[j++]=rand()}
     NR==FNR {next}
     FNR==1 {n=asort(a,b); cutoff=b[n/2]}
     $2!=2 {print; next}
     a[i++]<=cutoff {print}' input input
awk'开始{srand()}
NR==FNR&$2==2{a[j++]=rand()}
NR==FNR{next}
FNR==1{n=asort(a,b);cutoff=b[n/2]}
$2!=2{打印;下一个}

a[i++]为了保证约50%的删除,我们需要(提前)知道存储“2”值的许多“行”是谁

awk 'function get_random(total) {
        while(1){
           a = sprintf(int(total * rand()))
           if (!( a in b )){
              b[a]++
              if (++i>int(total/2))
                 break
              }
           }
        }
     BEGIN{srand();k=0}
     NR==FNR{if ($2==2){total++};next}
     !i{get_random(total)}
     $2!=2{print;next}
     (sprintf(++k) in b){print}' inputfile inputfile
get_random
:将获取受影响记录的数量作为参数,而while循环将在关联数组(b)中存储总计/2(随机和非重复)值(使用转换为字符串)

NR==FNR{if($2==2){total++};next}
:第二个字段等于2的出现次数

!i{get_random(total)}
:当counter
i
为空并且我们在文件的第二次迭代时调用函数

2美元=2{print;next}
:打印未受影响的行


(b中的sprintf(++k){print}
:仅当计数器在数组中时才打印筛选行(用随机值填充)。

您可以使用perl、sed或awk吗?或者你真的只限于bash/shell吗?我可以使用awk或sed。也许我误解了,但是使用这种策略不能保证删除50%。您可以不使用“2”行结束(或全部使用)。我同意@klashxx。它给我随机的结果,有时我没有2,有时我有50%,有时我有超过50%。我该如何解决这个问题?@Rafat在你的问题中,据说有“许多行”。如果有“许多行”,那么这个算法将给你将近一半的删除。一枚普通硬币的抛投行为类似:经过多次抛投后,不太可能正好有一半是正面,但接近一半是正面。如果你只需要一半,那么也许克拉什的方法对你更合适。@Rafat我刚刚添加了一个版本,正好能达到50%。@John1024非常感谢你。我制作了一个测试文件,并试图在上面实现你的脚本,但奇怪的是,有时它会给我50%的删除率,有时它会给我更少的删除率。应该是这样吗?