2012-12-19 4 views
6

Voglio sostituire la stringa TaskID_1 con una sequenza che inizia da 1001 e questo TaskID_1 può esistere un numero qualsiasi di righe nel mio file di input. Allo stesso modo ho bisogno di sostituire tutte le occorrenze di TASKID_2 nel mio file di input con il successivo valore di sequenza 1002.Sostituzione di un modello di stringa con un'altra sequenza in unix

file di input:

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 

Il file di output dovrebbe essere simile:

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 

risposta

9

Ecco un modo utilizzando awk:

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

o meno verboso:

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

Risultati:

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 

Per il primo esempio, il separatore separatore di file e file di output sono impostati su un singolo carattere pipe. Questo è impostato nel blocco BEGIN, in modo che venga eseguito solo una volta e non su ogni riga di input. Quindi impostiamo la terza colonna come uguale a 1000 più una variabile incrementale. Potremmo usare ++i come variabile, ma potremmo invece usare NR (che è l'abbreviazione di numero/numero di riga del record) e questo eviterebbe quindi la necessità di creare una variabile extra. Il 1 alla fine abilita la stampa di default. Una soluzione più dettagliato sarà simile:

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

EDIT:

Utilizzando il file di dati aggiornati, provare:

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

Risultati:

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, che è quasi esattamente come lo farei. – ghoti

+1

+1 dannatamente, bastonatemi (l'ultima soluzione sopra, cioè) :-). –

+1

Grazie Steve .. Questa soluzione funziona perfettamente. – Ramkumar

2

Non riesco a trovare una soluzione migliore rispetto a quella proposta in awk.

Quindi ecco una soluzione peggiore, utilizzando solo 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 

E ' "peggiore" solo perché sarà molto più lento di awk, che è veloce ed efficiente con questo tipo di problema.

+0

Tempo per un file con linee 1M: 66 secondi. Molto lento, ma ancora ok da usare e facile da capire. – erik

+0

Se si sostituisce $ ((++ n)) con $ (($ {f3 # * _} + 1000)), allora è quello che voleva la domanda. E il tempo che ho misurato era per la versione corretta. – erik

+0

Oh, e devi sostituire 'f1 f2 _f4 f5 f6' con' f1 f2 f3 f4 f5 f6'. – erik

4

soluzione A Perl usando la logica di Steve di aggiungere 1000:

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

Questo sostituisce il 'TaskID_n' con 1000 + n. 'e' è usato per valutare la sostituzione.

+0

Tempo per un file con linee 1M: 6,363 secondi. Un po 'più lento di awk ma più facile da capire se conosci le espressioni regolari. – erik

1

Sostituire TaskID_ con 100, questo è super facile con sed per gli ID cifra singola:

$ 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 

Per memorizzare questa modifica al file utilizzare l'opzione -i:

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

Nota: questo funziona per TaskID_[0-9] se si desidera che TaskID_23 sia mappato su 1023 quindi non lo farà, questo dovrebbe mappare TaskID_23 a 10023.

+1

Tempo per un file con linee 1M: 0,861 secondi. Più veloce, ma solo da 1000 a 1009. – erik

+0

@er buon lavoro, ho trovato il tuo benchmarking molto interessante. –

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

Provato In basso:

> 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

Tempo per un file con linee 1M: 7.463 secondi. Più lento (tranne bash) e solo da 1000 a 1009. – erik