Как я управляю последним соответствием строки в тексте? У меня есть конфигурационный файл, в котором я хочу изменить определенное значение:
val1=0
val2=a
val3=?
val2=lol
Я только хочу изменить последнюю строку, соответствующую значению к grep для. sed -i 's/\(^val2=\)/\1yes/'
хорошее начало, но заменяет обоих val2
строки вместо только последнего.
Я отметил вопрос очень в общем как Unix, потому что я открыт для любого решения: sed или awk, Perl или Ruby, Bash или что бы то ни было. Более короткое решение более сексуально, чем полный рот один.
Лучшее, которое я придумал, является этим:
tac config |while read LINE; do
if [ "$DONE" != 1 ] && echo "$LINE" |grep '^\s*val2\s*=' >/dev/null; then
echo "$LINE" |sed 's/^\(\s*val2\s*=\s*\)/\1yes/'
DONE=1
else
echo "$LINE"
fi
done |tac >config.new
Но это не чувствует себя подобно быстрым-и-грязным конвейерам, которые я люблю за такую общую задачу.
На основе сценария, найденного здесь:
sed -r ':0;/^val2=/!b;:1;$!N;/\n.*word/{h;s/\n[^\n]*$//p;g;s/^.*\n//};$!b 1;s/^(.*)(val2=)[^\n]*/\1\2yes/' file
Общее представление: считайте вход в блоках, разделенных \nval2=
. Распечатайте каждый блок, как, за исключением последнего блока, где мы изменяем текст до первой новой строки. Вот относительно простое решение простофили, которое обрабатывает большинство случаев:
gawk -v 'RS=\nval2=' -v ORS= \
'RT {print $0 RT} !RT {sub(/[^\n]*/, "yes"); print $0}'
Это предполагает, что первая строка не запускается с val2=
и это там - по крайней мере одно соответствие. Фиксация обоих дефектов значительно усложняет сценарий:
gawk -v 'RS=\nval2=' -v ORS= \
'!RT {if (NR==1) sub(/^val2=[^\n]*/, "val2=yes"); else sub(/[^\n]*/, "yes")}
{print $0 RT}'
Вот решение для Perl на основе того же общего принципа, но чтение целого файла сразу. Я нахожу это более ясным, потому что это не должно обрабатывать особые случаи (кроме пустого файла).
perl -e 'undef $/;
@chunks = split /(?=^val2=)/m, <>;
$chunks[@chunks-1] =~ s/(?<=^val2=).*/yes/ if @chunks;
print @chunks'
С Perl расширил regexps, мы можем использовать единственную regexp замену. Просто соответствуйте ^val2=
это не сопровождается другим ^val2=
:
perl -e 'undef $/; $_=<>; s/^val2=.*\n(?!.*\nval2=)/val2=yes\n/m; print'
Я пытался использовать в своих интересах Python rsplit
который может отделить последние поля N, но сдался, когда я не мог заставить это работать, не будучи намного более загадочным что мои решения для Perl.