我有一个如下列表:
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
由于您的问题被标记为sed
和bash
,这里有一些完整性的示例。
仅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