Я хочу заменить в моем файле только последнюю строку "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'
Спасибо
Он изменяет только последнюю строку, потому что вы сообщаете об этом: $ - это адрес последней строки, и вы используете его как первую строку диапазона адресов.
Вы хотите, чтобы не последние строки delay = превратились в одну пустую строку? Достаточно ли будет полностью исчезнуть? Достаточно ли просто быть пустым?
Вы можете отсортировать файл? Что, если один и тот же ключ встречается с разными значениями? Достаточно ли мал файл, чтобы можно было использовать медленную логику? Нужно ли это делать?
Кроме того, здесь отсутствуют детали. vtsisc_delay не встречается ни в одном из них. ens_delay встречается только в ожидаемом вами выходе. Где код в контексте?
@PaulHodges Я уже внес некоторые исправления
Покажите нам простейший ~ полный пример кода и его выходных данных и поясните свои требования. Вы хотите, чтобы 1) все, кроме ПОСЛЕДНЕЙ строки в файле, содержащие строку delay, были удалены, без каких-либо дополнительных особых условий? и 2) вы хотите, чтобы эта строка добавляла ens_ к delay, да? И порядок строк специфичен, или вы могли бы отсортировать файл? Что еще более важно, насколько велик файл? Это единственная строка, для которой вы хотите удалить дубликаты?





Вы не можете делать такие вещи с помощью 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 или любого количества других языков. Только не sed.
У этого монстра:
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
можешь сказать мне, что здесь делает test.txt раньше | хвостик ? потому что у меня ошибка sed: can't read test.txt: No such file or directory expr: syntax error sed: -e expression #1, char 3: unexpected , спасибо
Я заменил только your_file.txt своим файлом iinput, так что я должен делать с test.txt
он удаляет только дубликат и сохраняет последнее слово, не заменяя его. Спасибо
@Hamadagm, он заменяет последнее слово, у меня на выходе есть ens_delay='9'.
Как уже упоминалось в другом месте, 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
Это просто сохраняет последнюю увиденную строку в массиве, ключ которого является именем переменной, а затем распечатывает содержимое массива в неизвестном порядке.
он работает, но порядок строк в моем файле изменился, и как я могу сохранить изменения после этой командной строки. Спасибо
Я устал от вашей последней команды соблюдать порядок моих строк, но я потерял порядок. Спасибо
@Hamadagm, да, это то, что я сказал в ответе. Если вас не волнует порядок, используйте последнюю версию, которая не сохраняет порядок вывода. Если вы ДЕЙСТВИТЕЛЬНО заботитесь о порядке вывода, используйте первую версию, которая поддерживает отдельный массив (o[]) для сохранения порядка.
Если я правильно понимаю ваши спецификации, это должно сделать то, что вам нужно. Учитывая infile 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 считывает ведущие числа как селекторы строк, поэтому что делает этот сценарий команд -
Во-первых, sed автоматически печатает строки, если не указано иное, поэтому по умолчанию он просто печатает каждую строку. Сценарий изменяет это.
/delay/ { ... } - это селектор записи на основе шаблонов. Он будет применять команды между {} ко всем строкам, которые соответствуют /delay/, поэтому ему не нужен другой grep - он обрабатывает это сам. Внутри фигурных скобок сценарий выполняет две функции.
Во-первых, 14!d говорит (только если в этой строке есть delay, а он будет), что если номер строки 14, выполните нет (!) delete запись. Поскольку все остальные строки с delay не будут строкой 14 (или любым другим значением последней, созданной предыдущей командой), они получат deleted, который автоматически перезапустит цикл и прочитает следующую запись.
Во-вторых, если номер строки является 14, то delete не удалится, и поэтому перейдет к s/delay/ens_delay/, который обновит ваше значение.
Для всех строк, которые не соответствуют /delay/, sed просто печатает их как есть.
ваша команда работает правильно, но я хочу сохранить свои изменения в файле после выполнения этой команды: last=$( grep -n delay x|tail -1|sed 's/:.*//' ) | sed '/delay/ { '$last'!d; '$last' s/delay/ens_delay/; }' x Чем вы
и я вижу, что только sed работает sed '/delay/ { '$last'!d; '$last' s/delay/ens_delay/; }' x, можете ли вы объяснить, нужно ли мне тоже использовать grep?
Теперь он работает, но вот так и не требует grep sed -i '/delay/ { '$last'!d; '$last' s/delay/ens_delay/; }' x. Вы можете объяснить, почему не нужен grep, спасибо
если вы один раз запустили строку last=$( grep -n delay x|tail -1|sed 's/:.*//' ), то last все равно должен быть установлен в вашей среде. Попробуйте так: echo $last - должен быть номер строки. затем попробуйте это - unset last - и запустите снова. Скорее всего, не получится. Добавлю некоторые пояснения к решению. Когда вы будете готовы сделать изменения постоянными, либо перенаправьте вывод в новый файл, либо добавьте аргумент -i в sed.
Это может сработать для вас (GNU sed):
sed '/^delay=/,$!b;/^delay=/!H;//{x;s/^[^\n]*\n\?//;/./p;x;h};$!d;x;s/^/ens_/' file
Строки перед началом первой строки delay= следует печатать как обычно. В противном случае строка, начинающаяся с delay=, сохраняется в удерживаемом пространстве, а последующие строки, которые не начинаются с delay=, добавляются к ней. Если пространство удержания уже содержит такие строки, первая строка удаляется, а оставшиеся строки печатаются до того, как пространство удержания заменяется текущей строкой. В конце файла первая строка удерживаемого пространства изменяется, чтобы добавить строку ens_, а затем печатается все удерживаемое пространство.
В sed нет хорошего способа узнать, достигли ли вы последнего появления некоторого шаблона в нескольких строках.