快速从bash中的号码列表中删除号码一次的方法

时间:2019-02-21 17:03:49

标签: bash sorting

我有一个数字列表文件。

号码列表

0000000 00eb 00f4                              
0000003

,还有另一个文件,该文件是要删除的数字列表,仅一次

numers_to_remove

40426
140
26
3502
140
899320

所以输出文件应该是

140
3502

仅删除一次,以使140保持不变,因为它在list_of_numbers中出现了两次。

我现在正在做

40426
26
140
899320

有什么更快的方法来进行bash吗? 我将在此之后对这些数字进行排序,因此数字的顺序并不重要。

3 个答案:

答案 0 :(得分:0)

一个sed应该快很多:

list_of_numbers=(
    40426 140 26
    3502 140 899320
)

numbers_to_remove=(
    140 3502
)

printf "%s\n" "${list_of_numbers[@]}" |
sed "$(printf '0,/^%d$/s///\n' "${numbers_to_remove[@]}")/^$/d"

将输出:

40426
26
140
899320
  • printf重复它的格式字符串作为参数。因此printf "A %d" 1 2将输出A 1A 2
  • 首先,我们在单独的换行符上输出数字列表
  • 然后我们将要删除的数字列表中的每个数字的sed参数格式设置为0,/^<number here>$/s///<newline>。换行符用于分隔sed命令。
  • 最后一个sed命令用于删除空行,即。 /^$/d-删除没有内容的行。

答案 1 :(得分:0)

首先将要删除的所有数字存储在数组中。
处理完第一个文件(FNR==NR)后,继续第二个文件。
在remove数组中找到值后,将其从数组中删除并查看下一行。
当值不在数组中时打印它。

awk 'FNR==NR{a[$0];next}
     $0 in a{delete a[$0];next}
     {print}' numbers_to_remove list_of_numbers

答案 2 :(得分:0)

with awk-这确实需要预排序的记录。只要两个文件使用相同的排序方案,顺序就无关紧要。

awk '
  BEGIN{ getline skipnum < "numbers_to_remove"; old=""; }
  { if ( $0 == skipnum && old != skipnum ) {
       old = skipnum;
       getline skipnum < "a";
       next;
    } else print;
  }
' list_of_numbers

BEGIN从列表中预读一行以跳过。 在每个记录上,如果设置了skipnum并与当前行匹配,
-然后尝试读取下一个skipnum-失败应将其保留为空。
-next跳过打印该记录。
否则打印当前记录。

这是对每个文件的快速单次读取。

如果您不想对其进行预排序,则使用关联数组并删除找到的每个元素。

awk '
  BEGIN {
    while (getline skipnum < "numbers_to_remove") { skips[skipnum] = 1; }
  }
  { if ( $0 in skips ) {
       delete skips[$0];
       next;
    } else print;
  }
' list_of_numbers