2014-01-24 3 views
2

У меня есть список, как ниже:Заменить повторяющиеся элементы в списке с уникальными идентификаторами

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 

(кроме реального списка составляет 40 миллионов строк).

Там повторяются элементы во втором столбце (то есть «„)

Я хочу, чтобы заменить их уникальными identifers (например,“.1" ,» .2" ,»0,3" ... "п")

Я пытался сделать это с помощью петли Баш/SED комбинации, но это не работает ...

неудачная попытка:

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

(Esse я пытался заставить sed заменить каждый n th "." с помощью ". . п», но это не сработало)

ответ

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}).

Обычная Баш альтернатива:

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

Я понятия не имею, как это сделать с помощью 'СЭД . Однако некоторые из ответов [здесь] (http://stackoverflow.com/questions/12496717/sed-replace-pattern-with-line-number) могут помочь. – Mat

+0

+1 для приятного и простого awk. – anubhava

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 
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 не может увеличивать переменные, это должно быть сделано извне.

Для каждой строки, приращение $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 
Смежные вопросы