我有一个如下所示的列表:
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。“,但这不起作用)。
答案 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)
由于您的问题已标记为sed
和bash
,因此以下是一些完整性示例。
仅限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