用唯一标识符在列表中替换重复的元素



我有一个如下列表:

1 . Fred 1 6 78 8 09
1 1 Geni 1 4 68 9 34
2 . Sam 3 4 56 6 89
3 . Flit 2 4 56 8 34
3 4 Dog 2 5 67 8 78
3 . Pig 2 5 67 2 21

(实际列表为4000万行)。

第二列中有重复的元素(即"。")

我想用唯一的标识符(例如" .1"," .2"," .3" ..."。

我试图通过bash循环/sed组合来做到这一点,但它不起作用...

尝试失败:

for i in 1..4
  do
    sed -i "s_//._//."$i"_"$i""
  done 

(从本质上讲,我试图替换每个 n th。

这是一种使用awk进行操作的方法(假设您的文件称为input

$ awk '$2=="."{$2="."++counter}{print}' input 
1 .1 Fred 1 6 78 8 09
1 1 Geni 1 4 68 9 34
2 .2 Sam 3 4 56 6 89
3 .3 Flit 2 4 56 8 34
3 4 Dog 2 5 67 8 78
3 .4 Pig 2 5 67 2 21

awk程序将第二列($2)替换为通过串联.形成的字符串和预入的计数器(++counter),如果第二列正好是.。然后,它打印出所获得的所有列(是否修改了$2)({print})。

普通狂欢替代:

c=1
while read -r a b line ; do
  if [ "$b" == "." ] ; then
    echo "$a ."$((c++))" $line"
  else
    echo "$a $b $line"
  fi
done < input

由于您的问题被标记为sedbash,这里有一些完整性的示例。

仅bash

使用参数扩展。第二列将是唯一的,但不是顺序:

i=1; while read line; do echo ${line/./.$((i++))}; done < input
1 .1 Fred 1 6 78 8 09
1 1 Geni 1 4 68 9 34
2 .3 Sam 3 4 56 6 89
3 .4 Flit 2 4 56 8 34
3 4 Dog 2 5 67 8 78
3 .6 Pig 2 5 67 2 21

bash sed

sed不能增加变量,必须在外部进行。

对于每行,如果行包含一个.,请增加$i,然后让sed附加$i之后.

i=0                                    
while read line; do                 
    [[ $line == *.* ]] && i=$((i+1))   
    sed "s#.#.$i#" <<<"$line" 
done < input                           

输出:

1 .1 Fred 1 6 78 8 09
1 1 Geni 1 4 68 9 34
2 .2 Sam 3 4 56 6 89
3 .3 Flit 2 4 56 8 34
3 4 Dog 2 5 67 8 78
3 .4 Pig 2 5 67 2 21

您可以使用此命令:

awk '{gsub(/./,c++);print}' filename

输出:

1 0 Fred 1 6 78 8 09
1 1 Geni 1 4 68 9 34
2 2 Sam 3 4 56 6 89
3 3 Flit 2 4 56 8 34
3 4 Dog 2 5 67 8 78
3 5 Pig 2 5 67 2 21

相关内容

  • 没有找到相关文章

最新更新