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

时间:2014-01-24 17:10:46

标签: bash replace sed rename

我有一个如下所示的列表:

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”......“。 n ”)

我尝试使用bash循环/ sed组合执行此操作,但它不起作用...

尝试失败:

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

(基本上,我试图让sed用“。 n ”替换每个 n th。“,但这不起作用)。

3 个答案:

答案 0 :(得分:5)

以下是使用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})。

普通bash替代方案:

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

答案 1 :(得分:1)

由于您的问题已标记为sedbash,因此以下是一些完整性示例。

仅限Bash

使用parameter expansion。第二列将是唯一的,但不是顺序的:

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

答案 2 :(得分:0)

您可以使用此命令:

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