2012-12-19 8 views
6

Chcę zamienić ciąg TaskID_1 na sekwencję rozpoczynającą się od 1001, a ta TaskID_1 może zawierać dowolną liczbę linii w moim pliku wejściowym. Podobnie muszę zastąpić wszystkie wystąpienia TASKID_2 w moim pliku wejściowym kolejną wartością sekwencji 1002.Zastępowanie wzorca ciągu inną sekwencją w systemie Unix

plik wejściowy:

12345|45345|TaskID_1|dksj|kdjfdsjf|12 
1245|425345|TaskID_1|dksj|kdjfdsjf|12 
1234|25345|TaskID_2|dksj|kdjfdsjf|12 
123425|65345|TaskID_2|dksj|kdjfdsjf|12 
123425|15325|TaskID_1|dksj|kdjfdsjf|12 
11345|55315|TaskID_2|dksj|kdjfdsjf|12 
6345|15345|TaskID_3|dksj|kdjfdsjf|12 
72345|25345|TaskID_4|dksj|kdjfdsjf|12 
9345|411345|TaskID_3|dksj|kdjfdsjf|12 

Plik wyjściowy powinien wyglądać następująco:

12345|45345|1001|dksj|kdjfdsjf|12 
1245|425345|1001|dksj|kdjfdsjf|12 
1234|25345|1002|dksj|kdjfdsjf|12 
123425|65345|1002|dksj|kdjfdsjf|12 
123425|15325|1001|dksj|kdjfdsjf|12 
11345|55315|1002|dksj|kdjfdsjf|12 
6345|15345|1003|dksj|kdjfdsjf|12 
72345|25345|1004|dksj|kdjfdsjf|12 
9345|411345|1003|dksj|kdjfdsjf|12 

Odpowiedz

9

Oto jeden ze sposobów korzystania awk:

awk 'BEGIN { FS=OFS="|" } { $3=1000 + NR }1' file 

lub mniej --long:

awk -F '|' '{ $3=1000 + NR }1' OFS='|' file 

Wyniki:

12345|45345|1001|dksj|kdjfdsjf|12 
1245|425345|1002|dksj|kdjfdsjf|12 
1234|25345|1003|dksj|kdjfdsjf|12 
123425|65345|1004|dksj|kdjfdsjf|12 
123425|15325|1005|dksj|kdjfdsjf|12 
11345|55315|1006|dksj|kdjfdsjf|12 
6345|15345|1007|dksj|kdjfdsjf|12 
72345|25345|1008|dksj|kdjfdsjf|12 
9345|411345|1009|dksj|kdjfdsjf|12 

W pierwszym przykładzie separator plików i plik wyjścia są ustawione na pojedynczą postać rury. Jest to ustawione w bloku BEGIN, tak że jest wykonywane tylko raz, a nie w każdym wierszu wejścia. Następnie ustawiamy trzecią kolumnę na równą 1000 plus zmienną zwiększającą. Moglibyśmy użyć ++i jako tej zmiennej, ale moglibyśmy zamiast tego użyć NR (co jest skrótem od numeru rekordu/numeru linii), a to pozwoliłoby uniknąć potrzeby utworzenia dodatkowej zmiennej. Model 1 na końcu domyślnie umożliwia drukowanie. Bardziej szczegółowa rozwiązaniem będzie wyglądać następująco:

awk 'BEGIN { FS=OFS="|" } { $3=1000 + NR; print }' file 

EDIT:

Korzystanie zaktualizowany plik danych, spróbuj:

awk 'BEGIN { FS=OFS="|" } { sub(/.*_/,"",$3); $3+=1000 }1' file 

Wyniki:

12345|45345|1001|dksj|kdjfdsjf|12 
1245|425345|1001|dksj|kdjfdsjf|12 
1234|25345|1002|dksj|kdjfdsjf|12 
123425|65345|1002|dksj|kdjfdsjf|12 
123425|15325|1001|dksj|kdjfdsjf|12 
11345|55315|1002|dksj|kdjfdsjf|12 
6345|15345|1003|dksj|kdjfdsjf|12 
72345|25345|1004|dksj|kdjfdsjf|12 
9345|411345|1003|dksj|kdjfdsjf|12 
+1

** + 1 ** ... yup, że chodzi tylko o dokładnie, jak bym to zrobić. – ghoti

+1

+1 darn, pokonaj mnie (ostatnie rozwiązanie powyżej) :-). –

+1

Dzięki Steve .. To rozwiązanie działa świetnie. – Ramkumar

2

Nie mogę wymyślić lepszego rozwiązania niż ten sugerowany przez steka w awk.

Oto gorsze rozwiązanie, używając tylko bash.

#!/bin/bash 

IFS='|' 

while read f1 f2 f3 f4 f5 f6; do 
    printf '%s|%s|%d|%s|%s|%s\n' "$f1" "$f2" "$((${f3#*_}+1000))" "$f4" "$f5" "$f6" 
done < input 

To „gorzej” tylko dlatego, że będzie to znacznie wolniej niż awk, który jest szybki i skuteczny z tego rodzaju problemu.

+0

Czas na plik z 1M linii: 66 sekund. Bardzo powolny, ale nadal w użyciu i łatwy do zrozumienia. – erik

+0

Jeśli zastąpisz $ ((++ n)) przez $ (($ {f3 # * _} + 1000)), to jest to, o co chodziło pytanie. Czas zmierzyłem dla poprawionej wersji. – erik

+0

Aha, i musisz zastąpić 'f1 f2 _ f4 f5 f6' przez' f1 f2 f3 f4 f5 f6'. – erik

4

roztwór Perl pomocą logiki Steve dodawania 1000:

perl -pne 's/TaskID_(\d+)/$1+1000/e;' file 

Zastępuje 'TaskID_n' 1000 + n. "e" służy do oceny zamiennika.

+0

Czas na plik z 1M liniami: 6.363 sekundy. Nieco wolniejszy od awk, ale łatwiejszy do zrozumienia, jeśli znasz wyrażenia regularne. – erik

1

Wymień TaskID_ z 100, to jest bardzo proste ze sed dla pojedynczych cyfr ID:

$ sed 's/TaskID_/100/' file 
12345|45345|1001|dksj|kdjfdsjf|12 
1245|425345|1001|dksj|kdjfdsjf|12 
1234|25345|1002|dksj|kdjfdsjf|12 
123425|65345|1002|dksj|kdjfdsjf|12 
123425|15325|1001|dksj|kdjfdsjf|12 
11345|55315|1002|dksj|kdjfdsjf|12 
6345|15345|1003|dksj|kdjfdsjf|12 
72345|25345|1004|dksj|kdjfdsjf|12 
9345|411345|1003|dksj|kdjfdsjf|12 

Aby zapisać tę zmianę z powrotem do pliku należy wybrać opcję -i:

sed -i 's/TaskID_/100/' file 

Uwaga: działa to dla TaskID_[0-9], jeśli chcesz TaskID_23 zmapowany do 1023 to nie będzie, to będzie mapować TaskID_23 na 10023.

+1

Czas na plik z 1M liniami: 0,861 sekundy. Najszybszy, ale tylko za 1000 do 1009. – erik

+0

@ dobry dobry dzieło, uznałem twój benchmarking bardzo interesujący. –

0
perl -F"\|" -lane '$F[2]=~s/.*_/100/g;print join("|",@F)' your_file 

Testowany Poniżej:

> cat temp 
12345|45345|TaskID_1|dksj|kdjfdsjf|12 
1245|425345|TaskID_1|dksj|kdjfdsjf|12 
1234|25345|TaskID_2|dksj|kdjfdsjf|12 
123425|65345|TaskID_2|dksj|kdjfdsjf|12 
123425|15325|TaskID_1|dksj|kdjfdsjf|12 
11345|55315|TaskID_2|dksj|kdjfdsjf|12 
6345|15345|TaskID_3|dksj|kdjfdsjf|12 
72345|25345|TaskID_4|dksj|kdjfdsjf|12 
9345|411345|TaskID_3|dksj|kdjfdsjf|12 
> perl -F"\|" -lane '$F[2]=~s/.*_/100/g;print join("|",@F)' temp 
12345|45345|1001|dksj|kdjfdsjf|12 
1245|425345|1001|dksj|kdjfdsjf|12 
1234|25345|1002|dksj|kdjfdsjf|12 
123425|65345|1002|dksj|kdjfdsjf|12 
123425|15325|1001|dksj|kdjfdsjf|12 
11345|55315|1002|dksj|kdjfdsjf|12 
6345|15345|1003|dksj|kdjfdsjf|12 
72345|25345|1004|dksj|kdjfdsjf|12 
9345|411345|1003|dksj|kdjfdsjf|12 
> 
+0

Czas na plik z 1M linii: 7,463 sekundy. Najwolniejszy (z wyjątkiem bash) i tylko dla 1000 do 1009. – erik