Замена многострочного фрагмента sed

Программирование на sh, быть может немного про альтернативные языки
Правила форума
Убедительная просьба юзать теги [code] при оформлении листингов.
Сообщения не оформленные должным образом имеют все шансы быть незамеченными.
Dmitriy_K
сержант
Сообщения: 200
Зарегистрирован: 2009-04-07 6:22:33
Откуда: г.Королёв

Замена многострочного фрагмента sed

Непрочитанное сообщение Dmitriy_K » 2010-10-05 18:02:44

Кто-нибудь может подсказать как построить регулярное выражение для поиска sed такого блока из нескольких строк?

Код: Выделить всё

8) TERM=ansi-lwp; export TERM
   BASEDIR=/home/dir ; export BASEDIR
        . $BASEDIR/.setup
        cd $BASEDIR
        TERM=ansi-lwp; export TERM
        prog copy
        exit
        ;;

q) echo ; echo "Goodbye, "`logname`" !"
У меня как-то не проходит конструкция с символами переноса строки "\n". Что-то не так делаю.

Хостинговая компания Host-Food.ru
Хостинг HostFood.ru
 

Услуги хостинговой компании Host-Food.ru

Хостинг HostFood.ru

Тарифы на хостинг в России, от 12 рублей: https://www.host-food.ru/tariffs/hosting/
Тарифы на виртуальные сервера (VPS/VDS/KVM) в РФ, от 189 руб.: https://www.host-food.ru/tariffs/virtualny-server-vps/
Выделенные сервера, Россия, Москва, от 2000 рублей (HP Proliant G5, Intel Xeon E5430 (2.66GHz, Quad-Core, 12Mb), 8Gb RAM, 2x300Gb SAS HDD, P400i, 512Mb, BBU):
https://www.host-food.ru/tariffs/vydelennyi-server-ds/
Недорогие домены в популярных зонах: https://www.host-food.ru/domains/

Dmitriy_K
сержант
Сообщения: 200
Зарегистрирован: 2009-04-07 6:22:33
Откуда: г.Королёв

Re: Замена многострочного фрагмента sed

Непрочитанное сообщение Dmitriy_K » 2010-10-05 18:31:11

Кое-что смог сделать, строки фрагмента находятся (к сожалению, не как единое целое). Но теперь не могу их заменить единым блоком, всё время или заменяется построчно или не работает.

Код: Выделить всё

sed -ne '/8) TERM=ansi-lwp.*/,/q)/ s/.*$/OK/p' test.txt
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK

Нефиг_чем_заняться
проходил мимо

Re: Замена многострочного фрагмента sed

Непрочитанное сообщение Нефиг_чем_заняться » 2010-10-05 21:27:45

На awk подойдет ?

Код: Выделить всё

#! /bin/sh

s='jljkj kjlkj kl
kljkljkljkl jkl
kljkljklj
fghfghfhf
8) TERM=ansi-lwp; export TERM
   BASEDIR=/home/dir ; export BASEDIR
        . \$BASEDIR/.setup
        cd \$BASEDIR
        TERM=ansi-lwp; export TERM
        prog copy
        exit
        ;;

q) echo ; echo "Goodbye, "`logname`" !"
11111
tretretrr uiy uihjnmbc ntr d j
yutyu  g786  ihjkhp9ujo.
12121212'


echo "${s}" | awk 'BEGIN {
    a="8\) TERM\=ansi\-lwp\; export TERM";                         # start block
    b="q\) echo \; echo \"Goodbye\, \".*\" \!\""                   # end block
    c="replace block-first line\nreplace block-second line\n"   # replace block
    RS=a
}
/a/,/b/ { print c;}'

Dmitriy_K
сержант
Сообщения: 200
Зарегистрирован: 2009-04-07 6:22:33
Откуда: г.Королёв

Re: Замена многострочного фрагмента sed

Непрочитанное сообщение Dmitriy_K » 2010-10-05 22:57:01

Большое спасибо! Сейчас попробую.
У меня почти получилось скриптом на sed:

Код: Выделить всё

#!/bin/sh

ZAM=`cat zam.txt`    #Многострочный текст на замену блока. В нём приходится предварительно экранировать все символы regex и выставлять "\" на концах строк.

/usr/bin/sed -ne "/8) TERM=ansi-lwp.*/,/q)/ s/.*/$ZAM/p" test.txt
Но отрабатывает он пока странно: выдаёт три замены подряд вместо одной, как хотелось бы.

Dmitriy_K
сержант
Сообщения: 200
Зарегистрирован: 2009-04-07 6:22:33
Откуда: г.Королёв

Re: Замена многострочного фрагмента sed

Непрочитанное сообщение Dmitriy_K » 2010-10-05 23:33:32

Да, скрипт на awk отрабатывает, спасибо! Пока только не могу придумать как сделать, чтобы он менял только нужный фрагмент текста, а не заменял весь текст.
Остаётся загадкой почему неправильно отрабатывает замена в sed. Пробовал проверить как отрабатывает поиск фрагмента для замены.

Код: Выделить всё

sed -ne "/8) TERM=ansi-lwp.*/,/q)/ s/.*/&/p" test.txt

8) TERM=ansi-lwp; export TERM
   BASEDIR=/home/dir ; export BASEDIR
        . \$BASEDIR/.setup
        cd \$BASEDIR
        TERM=ansi-lwp; export TERM
        prog copy
        exit
        ;;

q) echo ; echo "Goodbye, "`logname`" !"
Оказалось, всё правильно, находится только один нужный фрагмент. Почему же тогда замена вставляется три раза подряд? :st:
...А заменять нужно срочно в около 4тыс. файлов.

Dmitriy_K
сержант
Сообщения: 200
Зарегистрирован: 2009-04-07 6:22:33
Откуда: г.Королёв

Re: Замена многострочного фрагмента sed

Непрочитанное сообщение Dmitriy_K » 2010-10-05 23:52:20

Кажется, получилось, наконец. :Yahoo!:

Код: Выделить всё

/usr/bin/sed -ne "/8) TERM=ansi-lwp.*/,/q)/ s/.*\" !\"/$ZAM/p" test.txt
Оказалось, надо было regexp замены фрагмента дописать, как в конце последней строки фрагмента, и кавычки заэкранировать.
Но за awk всё равно спасибо!

Dmitriy_K
сержант
Сообщения: 200
Зарегистрирован: 2009-04-07 6:22:33
Откуда: г.Королёв

Re: Замена многострочного фрагмента sed

Непрочитанное сообщение Dmitriy_K » 2010-10-06 2:51:17

В конечном счёте настрогал такую штуку: :smile:

Код: Выделить всё

#!/bin/sh

ZAM=`cat zam.txt`

#Change dir for "find ." to "find /home/" etc.
#
(find . -name ".bash_profile_old*" -exec /usr/bin/grep -le '^while.*8 \]$' '{}' +) > changed_bash_profiles.txt

#Change ".bash_profile_old*" to ".bash_profile"
#
for i in `find . -type f -name ".bash_profile_old*" | xargs grep -le '^while.*8 \]$' | awk -F: '{print $1}'`
do
cp ${i} ${i}_1
/usr/bin/sed -i '' -e 's/^while.*8 \]$/while \[ "$i" != 1 -a "$i" != 2 -a "$i" != 3 -a "$i" != 4 -a "$i" != q -a "$i" != Q -a "$i" != 5 -a "$i" != 6 -a "$i" != 7 -a "$i" != 8 -a "$i" != 10 \]/' \
-e 's/echo "8).*(\/prog_dir2\/dbcopy)"$/echo "8) Punkt of menu (\/prog_dir2\/dbcopy)"\
echo "10) New punkt of menu"/' \
-e 's/^if \[ "\$i".*8 \]$/if [ "$i" != 1 -a "$i" != 2 -a "$i" != 3 -a "$i" != 4 -a "$i" != q -a "$i" != Q  -a "$i" != 5 -a "$i" != 6 -a "$i" != 7 -a "$i" != 8 -a "$i" != 10 ]/' \
-e "/8) TERM=ansi-lwp.*/,/q)/ s/.*\" !\"/$ZAM/" \
${i}
done
Естественно, тут дан пример тестового, полностью безопасного скрипта.
В zam.txt требуется вставить текст нужно дополнительного многострочного фрагмента с заэкранированными символами regexp.
Надеюсь, ещё кому пригодится, а то я совсем не смог найти ни одного примера замены многострочного фрагмента текста.

Нефиг_чем_заняться
проходил мимо

Re: Замена многострочного фрагмента sed

Непрочитанное сообщение Нефиг_чем_заняться » 2010-10-06 7:25:00

Ни ФИГА себе !!!

Не, так не годится...

Код: Выделить всё

#! /bin/sh
##########################
# User defined variables
#-------------------------

srcfile='./srctest.txt'  # source file
outfile='./replaced.txt' # output file
zamena='./zamena.txt'    # file that contain replacement text

beginBlock='8\\) TERM\\=ansi.*'                # start string of text block that would be replaced. Should be the Regular expression.
endBlock='q\\) echo \\; echo \\"Goodbye\\,.*'  # end string of text block that would be replaced. Should be the Regular expression.

#
######################
# No user intervention beyond this point !!!!!!!!!
######################

cat "${srcfile}" | awk -v replace="${zamena}" -v a="${beginBlock}" -v b="${endBlock}" 'BEGIN {
    c=""; x=1;
    while (x != 0 && x != -1) {
        x=getline < replace
        if (x != 0) c=c $0 "\n";
    }
    if (x == -1) { print "Error while reading file: " replace "  Exiting..."; exit 1; }
}
{   if ( $0 ~a && skip == 0) { skip=1; print c; }
    if ( $0 ~b && skip == 1) { skip=0; next; }
}!skip' > "${outfile}"

exit 0
Правте заголовок в User defined variable для входного файла, файла с заменой и выходной файл ONLY. И не надо ничего нигде экранировать, усё будет пучком.
Сорри, что не SED-e, но меня достают куча его s,p,d и прочие сокращения, awk он как то ближе к человеческому языку

Dmitriy_K
сержант
Сообщения: 200
Зарегистрирован: 2009-04-07 6:22:33
Откуда: г.Королёв

Re: Замена многострочного фрагмента sed

Непрочитанное сообщение Dmitriy_K » 2010-10-06 11:43:26

Да, круто! :smile: :cz2:
Спасибо большое ещё раз!