«седь» заменить последний образец и удалить шаблон других - PullRequest
0 голосов
/ 13 ноября 2018

Я хочу заменить только последнюю строку «delay» на «ens_delay» в моем файле и удалить оставшуюся перед предыдущей:

Входной файл:

alpha_notify_teta=''
alpha_notify_check='YES'
text='CRDS'
delay=''
delay=''
delay=''
textfileooooop=''
alpha_enable='YES'
alpha_hostnames=''
alpha_orange='YES'
alpha_orange_interval='300'
alpha_notification_level='ALL'
expression='YES'
delay='9'
textfileooooop=''
alpha_enable='YES'
alpha_hostnames=''

Выходной файл: (ожидаемое значение)

alpha_notify_teta=''
alpha_notify_check='YES'
text='CRDS'

textfileooooop=''
alpha_enable='YES'
alpha_hostnames=''
alpha_orange='YES'
alpha_orange_interval='300'
alpha_notification_level='ALL'
expression='YES'
ens_delay='9'
textfileooooop=''
alpha_enable='YES'
alpha_hostnames=''

Здесь моя первая команда, но она не работает, потому что она будет работать, только если у меня задержка в последней строке.

sed -e '$,/delay/ s/delay/ens_delay/'

Моя вторая команда удалит все строки, содержащие «delay», даже «ens_delay» будет удален.

sed -i '/delay/d'

Спасибо

Ответы [ 5 ]

0 голосов
/ 14 ноября 2018

Это может сработать для вас (GNU sed):

sed '/^delay=/,$!b;/^delay=/!H;//{x;s/^[^\n]*\n\?//;/./p;x;h};$!d;x;s/^/ens_/' file

Строки перед началом первой строки delay= должны быть напечатаны как обычно. В противном случае строка начала delay= сохраняется в области удержания, и к ней добавляются последующие строки, которые не начинаются delay=. Если в области удержания уже есть такие строки, первая строка удаляется, а оставшиеся строки печатаются до замены области удержания текущей строкой. В конце файла в первую строку пространства удержания вносится поправка для добавления строки ens_, а затем печатается все пространство удержания.

0 голосов
/ 14 ноября 2018

Если я правильно понимаю ваши спецификации, это должно сделать то, что вам нужно.Данный инфиль x,

$: last=$( grep -n delay x|tail -1|sed 's/:.*//' )

Это grep - файл для всех строк с delay и возвращает их с номером строки, начинающимся с двоеточия.tail -1 захватывает последнюю из этих строк, игнорируя все остальные.sed 's/:.*//' удаляет двоеточие и фактическое содержимое строки, оставляя только число (здесь это было 14.)

Все это оценивается, чтобы присвоить 14 как $last.

$: sed '/delay/ { '$last'!d; '$last' s/delay/ens_delay/; }' x
alpha_notify_teta=''
alpha_notify_check='YES'
text='CRDS'
textfileooooop=''
alpha_enable='YES'
alpha_hostnames=''
alpha_orange='YES'
alpha_orange_interval='300'
alpha_notification_level='ALL'
expression='YES'
ens_delay='9'
textfileooooop=''
alpha_enable='YES'
alpha_hostnames=''

Извинения за уродливую связь.Это делает запись сценария с использованием значения $last, чтобы результат выглядел следующим образом: sed:

$: sed '/delay/ { 14!d; 14 s/delay/ens_delay/; }' x

sed считывает начальные числа как селекторы строк, так что этот сценарийкоманды do -

Во-первых, sed автоматически печатает строки, если не указано иное, поэтому по умолчанию он просто печатает каждую строку.Сценарий изменяет это.

/delay/ { ... } - селектор записей на основе шаблона.Он будет применять команды между {} ко всем строкам, которые соответствуют /delay/, поэтому ему не нужен еще один grep - он обрабатывает это сам.Внутри curly, скрипт делает две вещи.

Во-первых, 14!d говорит (только если эта строка имеет delay, что и будет), что если номер строки 14, не , а (!) d выберите запись.Поскольку все остальные строки с delay не будут строкой 14 (или любым другим значением последней из созданных ранее команд), они получат d выборку, которая автоматически перезапускает цикл и читает следующую запись.

Во-вторых, если номер строки равен 14, то он не будет d elete, и, следовательно, перейдет к s/delay/ens_delay/, который обновит ваше значение.

Длявсе строки, которые не соответствуют /delay/, sed, просто печатает их как есть.

0 голосов
/ 14 ноября 2018

Иметь этого монстра:

sed -e "1,$(expr $(sed -n '/^delay=/=' your_file.txt | tail -1) - 1)"'s/^delay=.*$//' \
    -e 's/^delay=/ens_delay=/' your_file.txt

Здесь:

  • sed -n '/^delay=/=' your_file.txt | tail -1 вернуть последнюю строку число обнаруженного шаблона (назовем его X)
  • expr используется для получения X-1 строки
  • "1,X-1"'[command]' означает «выполнить эту команду между первой и включенной строкой X-1 (я использовал двойные кавычки»чтобы расширение могло быть выполнено)
  • 's/^delay=.*$//' указанное [command]
  • -e 's/^delay=/ens_delay=/' следующее выражение для выполнения (произойдет только в последней строке)

Вывод:

alpha_notify_teta=''
alpha_notify_check='YES'
text='CRDS'



textfileooooop=''
alpha_enable='YES'
alpha_hostnames=''
alpha_hsm_backup_notification='YES'
alpha_orange='YES'
alpha_orange_interval='300'
alpha_notification_level='ALL'
expression='YES'
ens_delay='9'
textfileooooop=''
alpha_enable='YES'
alpha_hostnames=''
alpha_hsm_backup_notification='YES'

Если вы хотите удалить строки, а не оставлять их пустыми:

sed -e "1,$(expr $(sed -n '/^delay=/=' your_file.txt | tail -1) - 1)"'{/^delay=.*$/d}' \
    -e 's/^delay=/ens_delay=/' your_file.txt
0 голосов
/ 14 ноября 2018

Как уже упоминалось, sed не может знать, какое вхождение подстроки является последним.Но awk может отслеживать вещи в массивах.Например, следующее удалит все повторяющиеся назначения, а также попросит сделать замену:

awk 'BEGIN{FS=OFS="="} $1=="delay"{$1="ens_delay"} !($1 in a){o[++i]=$1} {a[$1]=$0} END{for(x=0;x<i;x++) printf "%s\n",a[o[x]]}' inputfile

Или выделено для удобства чтения / комментариев:

BEGIN {
  FS=OFS="="       # set the field separator, to help isolate the left hand side
}

$1=="delay" {
  $1="ens_delay"   # your field substitution
}

!($1 in a) {
  o[++i]=$1        # if we haven't seen this variable, record its position
}

{
  a[$1]=$0         # record the value of the last-seen occurrence of this variable
}

END {
  for (x=0;x<i;x++)          # step through the array,
    printf "%s\n",a[o[x]]    # printing the last-seen values, in the order
}                            # their variable was first seen in the input file.

Возможно, вам все равноо порядке переменных.Если это так, следующее может быть проще:

awk 'BEGIN{FS=OFS="="} $1=="delay"{$1="ens_delay"} {o[$1]=$0} END{for(i in o) printf "%s\n", o[i]}' inputfile

Это просто сохраняет последнюю увиденную строку в массиве, ключом которого является имя переменной, а затем распечатывает содержимое массива в неизвестном порядке.

0 голосов
/ 14 ноября 2018

Вы не можете делать такие вещи с помощью sed.В sed нет способа «смотреть вперед» и сказать, есть ли еще совпадения с шаблоном.Вы можете оглянуться назад, но этого будет недостаточно для решения этой проблемы.

Этот сценарий Perl решит ее:

#!/usr/bin/perl
use strict;
use warnings;
my ($seek, $replacement, $last, @new) = (shift, shift, 0);
open(my $fh, shift) or die $!;
my @l = <$fh>;
close($fh) or die $!;
foreach (reverse @l){
    if(/$seek/){
        if ($last++ == 0){
            s/$seek/$replacement/;
        } else {
            next;
        }
    }
    unshift(@new, $_);
}
print join "", @new;

Вызов как:

./script delay= ens_delay= inputfile

Я решил полностью исключить строки, которые вы намеревались удалить, а не сворачивать их в одну пустую строку.Если это действительно требуется, то это немного сложнее: первая такая строка в любом последовательном наборе (или, скорее, последний такой) должна быть перенесена в список вывода, и вы должны отслеживать, было ли это только что сделано, чтобы вы знали,нажать и в следующий раз.

Эту проблему также можно решить с помощью awk, python или любого количества других языков.Просто не седь.

...