Как заменить все, кроме последнего совпадения в файле, используя bash? - PullRequest
0 голосов
/ 06 ноября 2011

Предполагается использование bash с файлом конфигурации, например:

  1. param-a = aaaaaa
  2. param-b = bbbbbb
  3. param-foo = первый случай <- Заменить </b>
  4. param-c = cccccc
  5. # param-foo = первый комментарий foo<- прокомментировано: не заменяйте </i>
  6. param-d = dddddd
  7. param-e = eeeeee
  8. param-foo =второй случай <- Rreplace </b>
  9. param-foo = третий случай <- Последний активный: не заменять </b>
  10. param-x = xxxxxx1
  11. param-f = ffffff
  12. # param-foo = второй комментарий foo <- Комментарий: не заменять </i>
  13. param-x = xxxxxx2

В котором вы можете найти несколько закомментированных или незакомментированных строк param-foo, как вы можете прокомментировать все некомментированные param-foos, кроме самого последнего активногов результате:

  1. param-a = aaaaaa
  2. param-b = bbbbbb
  3. # param-foo = первый случай <- заменен </b>
  4. param-c = cccccc
  5. # param-foo = комментарий foo <- слева </i>
  6. param-d = dddddd
  7. param-e = eeeeee
  8. # param-foo = второй случай <- заменен </b>
  9. param-foo = третий случай <- Слева </b>
  10. param-x = xxxxxx1
  11. param-f = ffffff
  12. # param-foo = второй комментарий foo <- Слева </i>
  13. param-x = xxxxxx2

Две части вопроса:
1. Как это сделать только с одним известным повторяющимся параметром?
(только param-foo в приведенном выше примере)

2. Как это сделать со всеминесколько активных параметров одновременно?
(param-foo + param-x в приведенном выше примере)
Внимание: в этом случае я не знаю ранее названия повторяющихся параметров!

Спасибо

Ответы [ 4 ]

1 голос
/ 06 ноября 2011

Если приемлем awk, это будет сделано для param-foo и param-x :

awk -F= -v p='param-foo param-x'  'BEGIN { 
  ARGV[ARGC++] = ARGV[ARGC - 1]
  n = split(p, t, OFS)
  for (i = 0; ++i <= n;) _p[t[i]]
  }
NR == FNR {
    $1 in _p && nr[$1] = NR
  next
  }  
$1 in nr && FNR != nr[$1] {
  $0 = "# " $0 
  }1' infile

Вы можете использовать один параметр: p = param-x или добавить несколько параметров, разделенных пробелами: p = 'param-1 param-2 ... param-n' .

Редактировать: я предполагаю, что реальный входной файл выглядит так:

param-a=aaaaaa
param-b=bbbbbb
param-foo=first occurence
param-c=cccccc
# param-foo=commented foo
param-d=dddddd
param-e=eeeeee
param-foo=second occurence
param-foo=third occurence
param-x=xxxxxx1
param-f=ffffff
param-x=xxxxxx2

Дайте мне знать, если это не так.

Второе редактирование: предоставление решения для mawk пользователей:

awk -F= -v p='param-foo param-x'  'BEGIN { 
  n = split(p, t, OFS)
  for (i = 0; ++i <= n;) _p[t[i]]
  }
NR == FNR {
    $1 in _p && nr[$1] = NR
  next
  }  
$1 in nr && FNR != nr[$1] {
  $0 = "# " $0 
  }1' infile infile

Добавление решения по последнему требованию:

awk -F= 'NR == FNR {
  if (NF && !/^#/)
    _p[$1]++ && nr[$1] = NR
  next
  }    
$1 in nr && FNR != nr[$1] {
  FNR != nr[$1] && $0 = "# " $0 
  }1' infile infile
0 голосов
/ 07 ноября 2011

Это может сработать:

param="param-foo"
tac input_file |sed '/#/!{/'"$param"'/{x;/./{x;s/'"$param"'/# &/;t};x;h;}}'|tac >output_file

Для нескольких параметров:

cp input_file{,.backup}
params=(param-{foo,bar,baz})
tac input_file >backwards_file
for param in "${params[@]}"; do
    sed -i '/#/!{/'"$param"'/{x;/./{x;s/'"$param"'/# &/;t};x;h;}}' backwards_file
done
tac backwards_file >output_file

Повернуть input_file назад, предварительно отрисовать все, кроме первого вхождения $param с комментарием #, затем верните файл.

РЕДАКТИРОВАТЬ: Чтобы извлечь параметры из файла, используйте этот кусок кода:

params=($(sed -rn '/^#/d;/^$/!s/^\s*([^=]*).*/\1/gp' input_file | sort | uniq))
0 голосов
/ 06 ноября 2011

Я не полностью протестировал скрипт, но он работал на первом примере:

#!/bin/bash
input_file=/path/to/your/input/file    
last_occurence=`nl $input_file | grep 'param-foo' | grep -v '#' | tail -1 | awk -F" " '{print $1}'`
sed -i '/#/!s/param-foo/# param-foo/g' $input_file
sed -i "${last_occurence}s/# param-foo/param-foo/" $input_file

Это очень простая логика.Сначала мы получаем последнее вхождение param-foo, которое не комментируется.Первый сед идет и комментирует все param-foo, которые не комментируются.Второй sed использует line_number последнего вхождения param-foo и удаляет символ #.Вы можете легко обернуть это в функцию и использовать ее внутри цикла, предоставляя список параметров вместо одного.

0 голосов
/ 06 ноября 2011

Немного медленный для длинных файлов, но должен работать для всех параметров:

grep -v ^# $file |
cut -f1 -d= |
sort -u |
sed 's/^/grep -n . '$file' |
tac |
grep -m1 :/;s/$/= /' |
bash |
sed -r 's%([0-9]+):(.*)=(.*)%\1!s/^\2=/# \2=/%' |
sed -f- $file
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...