2015-10-02 2 views
1

file.txtкак заменить все, кроме строки интереса

fruits:banana,apple,grape,limon,orange,tomate, 
fruits:apple,limon, 
fruits:banana,grape,limon, 
fruits:orange,tomate,grape, 
fruits:banana, 
fruits:apple, 
fruits:banana,apple, 

Мне нужно заменить все, что отличается от «банан» для фруктов, и получить такой вывод:

fruits:banana,FRUIT,FRUIT,FRUIT,FRUIT,FRUIT, 
fruits:FRUIT,FRUIT, 
fruits:banana,FRUIT,FRUIT, 
fruits:FRUIT,FRUIT,FRUIT, 
fruits:banana, 
fruits:FRUIT, 
fruits:FRUIT,apple, 

Я попытался использовать awk, но я могу только заменить поля определенных строк.

Пример заменить все строки "Яблоко" по fruit2, или все строки "Яблоко" от fruit2 и все строки "Томат" или "оранжевые" по fruit3

awk -F":" '{ gsub(/apple/,"FRUIT2",$2); print }' OFS="," file.tx 

или

awk -F":" '{ gsub(/apple/,"FRUIT2",$2);;gsub(/tomate|orange/,"FRUIT3",$2); print }' OFS="," file.txt |sed "s/./:/7" 

fruits:banana,FRUIT2,grape,limon,FRUIT3,FRUIT3, 
fruits:FRUIT2,limon, 
fruits:banana,grape,limon, 
fruits:FRUIT3,FRUIT3,grape, 
fruits:banana, 
fruits:FRUIT2, 
fruits:banana,FRUIT2 

но Мне действительно нужно заменить все, что отличается от того, что для любой строки, например: fruit4

Как генерировать выходные данные следующим образом?

fruits:FRUIT4,FRUIT2,FRUIT4,FRUIT4,FRUIT3,FRUIT3, 
fruits:FRUIT2,FRUIT4, 
fruits:FRUIT4,FRUIT4,FRUIT4, 
fruits:FRUIT3,FRUIT3,FRUIT4, 
fruits:FRUIT4, 
fruits:FRUIT2, 
fruits:FRUIT4,FRUIT2 
+1

Вы хотите, чтобы результат выглядел как [this] (https://regex101.com/r/kP1cS7/1)? – OnlineCop

+0

Непонятно, хотите ли вы, чтобы определенные имена фруктов отображались на определенные новые значения (apple = FRUIT39) или каждое новое имя фрукта, сопоставленное новому значению на основе некоторой базы с числовым суффиксом (FRUIT1, FRUIT2 и т. Д.) Или что-то еще , –

ответ

1

Это AWK должно работать:

awk -F, -v OFS=, '{ 
    for (i=1; i<=NF; i++) 
    if ($i !~ /(^|:)banana$/) 
     sub(/[^:]+$/, "FRUIT", $i) 
} 1' file 

Выход:

fruits:banana,FRUIT,FRUIT,FRUIT,FRUIT,FRUIT, 
fruits:FRUIT,FRUIT, 
fruits:banana,FRUIT,FRUIT, 
fruits:FRUIT,FRUIT,FRUIT, 
fruits:banana, 
fruits:FRUIT, 
fruits:banana,FRUIT, 
+0

Этот подход потерпит неудачу с другими фруктами, например. если цель была яблоком вместо банана, а входной файл содержал ананас, то ананас не был бы преобразован в FRUIT. IMHO, включая часть до ':' в '$ 1', и поэтому в сравнениях действительно не правильный подход, и поэтому вызывает излишнюю сложность и потенциальные ошибки, чтобы закрасться. –

+1

Спасибо Ed, да, граница слова необходима для защиты Поиск. – anubhava

+1

Добро пожаловать. вы должны упомянуть, что это сделает его специфичным для gawk. Oh и nit-pick - gsub должен быть просто sub. –

1

Чтобы сделать процесс автоматизирован, вы можете сделать

awk -F '[:,]' -v OFS=, ' 
    { 
     for (i=2; i<=NF; i++) 
      if ($i) 
       if (seen[$i]) 
        $i = seen[$i] 
       else 
        $i = seen[$i] = "FRUIT" ++n 
     sub(OFS, ":") 
     print 
    } 
    END { 
     print "map:" 
     for (key in seen) 
      print key "\t" seen[key] 
    } 
' file 
fruits:FRUIT1,FRUIT2,FRUIT3,FRUIT4,FRUIT5,FRUIT6, 
fruits:FRUIT2,FRUIT4, 
fruits:FRUIT1,FRUIT3,FRUIT4, 
fruits:FRUIT5,FRUIT6,FRUIT3, 
fruits:FRUIT1, 
fruits:FRUIT2, 
fruits:FRUIT1,FRUIT2, 
map: 
orange FRUIT5 
tomate FRUIT6 
apple FRUIT2 
limon FRUIT4 
banana FRUIT1 
grape FRUIT3 
0

Если вы хотите некоторую гибкость в возможности указать ваше отображение старого к новому имен в командной строке:

$ cat tst.awk 
BEGIN { 
    FS="[:,]"; OFS="," 
    split(map,t) 
    for (i=1; i in t; i+=2) { 
     m[t[i]] = t[i+1] 
    } 
} 
{ 
    printf "%s:", $1 
    for (i=2;i<=NF;i++) { 
     if ($i in m)  { $i = m[$i] } 
     else if ("*" in m) { $i = m["*"] } 
     printf "%s%s", $i, (i<NF?OFS:ORS) 
    } 
} 

.

$ awk -v map='apple,FRUIT2,tomate,FRUIT3,*,FRUIT4' -f tst.awk file 
fruits:FRUIT4,FRUIT2,FRUIT4,FRUIT4,FRUIT4,FRUIT3,FRUIT4 
fruits:FRUIT2,FRUIT4,FRUIT4 
fruits:FRUIT4,FRUIT4,FRUIT4,FRUIT4 
fruits:FRUIT4,FRUIT3,FRUIT4,FRUIT4 
fruits:FRUIT4,FRUIT4 
fruits:FRUIT2,FRUIT4 
fruits:FRUIT4,FRUIT2,FRUIT4 

$ awk -v map='apple,BAZINGA,*,VEGGIE' -f tst.awk file 
fruits:VEGGIE,BAZINGA,VEGGIE,VEGGIE,VEGGIE,VEGGIE,VEGGIE 
fruits:BAZINGA,VEGGIE,VEGGIE 
fruits:VEGGIE,VEGGIE,VEGGIE,VEGGIE 
fruits:VEGGIE,VEGGIE,VEGGIE,VEGGIE 
fruits:VEGGIE,VEGGIE 
fruits:BAZINGA,VEGGIE 
fruits:VEGGIE,BAZINGA,VEGGIE 

$ awk -v map='apple,FRUIT2,tomate,FRUIT3' -f tst.awk file 
fruits:banana,FRUIT2,grape,limon,orange,FRUIT3, 
fruits:FRUIT2,limon, 
fruits:banana,grape,limon, 
fruits:orange,FRUIT3,grape, 
fruits:banana, 
fruits:FRUIT2, 
fruits:banana,FRUIT2, 
Смежные вопросы