Замена текста и символ перехода на новую строку
Модераторы: /dev/random, Модераторы разделов
-
- Сообщения: 201
Замена текста и символ перехода на новую строку
Здравствуйте.
Чтобы создать постустановочный скрипт мне необходима ваша помощь.
Вместо того, чтобы делать:
del /etc/rc.local
touch /etc/rc.local
chmod +x /etc/rc.local
echo "aaa" | tee -a "/etc/rc.local"
echo "bbb" | tee -a "/etc/rc.local"
...
echo "nnn" | tee -a "/etc/rc.local"
echo "exit 0" | tee -a "/etc/rc.local"
как сделать так же, но с помощью "sed -e 's/foo/bar/' myfile.txt". Не пойму - как быть со символами переноса строки в sed? Т.к., мне кажется, удалять rc.local и заново его создавать не есть элегантно?
Чтобы создать постустановочный скрипт мне необходима ваша помощь.
Вместо того, чтобы делать:
del /etc/rc.local
touch /etc/rc.local
chmod +x /etc/rc.local
echo "aaa" | tee -a "/etc/rc.local"
echo "bbb" | tee -a "/etc/rc.local"
...
echo "nnn" | tee -a "/etc/rc.local"
echo "exit 0" | tee -a "/etc/rc.local"
как сделать так же, но с помощью "sed -e 's/foo/bar/' myfile.txt". Не пойму - как быть со символами переноса строки в sed? Т.к., мне кажется, удалять rc.local и заново его создавать не есть элегантно?
Far behind the skies...
-
- Сообщения: 586
- Статус: -
Re: Замена текста и символ перехода на новую строку
xoomer писал(а): ↑01.05.2013 15:44Здравствуйте.
Чтобы создать постустановочный скрипт мне необходима ваша помощь.
Вместо того, чтобы делать:
del /etc/rc.local
touch /etc/rc.local
chmod +x /etc/rc.local
echo "aaa" | tee -a "/etc/rc.local"
echo "bbb" | tee -a "/etc/rc.local"
...
echo "nnn" | tee -a "/etc/rc.local"
echo "exit 0" | tee -a "/etc/rc.local"
как сделать так же, но с помощью "sed -e 's/foo/bar/' myfile.txt".
Но ведь в вашем примере вы ничего не заменяете, а просто стираете все, что было и создаете новый файл.
А что с ними? Они могут быть в bar (из s/foo/bar/), как и любые другие:
Код: Выделить всё
$ echo "abc" | sed -e's/b/B\nB/'
aB
Bc
Что же касается вашего скрипта, то, может быть, команда c\ - то, что вам надо? Вот пример: файл
Код: Выделить всё
$ cat 1.tmp
xxx
yyy
ttt
zzz
www
Скрипт заменяет все между строками /yyy/ и /zzz/ на новый текст
Код: Выделить всё
$ cat ./t.sh
#!/bin/sh
set -euf
rx='/yyy/,/zzz/cAAA\
BBB\
CCC'
sed -ie "$rx" 1.tmp
результат
Код: Выделить всё
$ ./t.sh
$ cat 1.tmp
xxx
AAA
BBB
CCC
www
Спасибо сказали:
-
- Сообщения: 201
Re: Замена текста и символ перехода на новую строку
> Но ведь в вашем примере вы ничего не заменяете, а просто стираете все, что было и создаете новый файл.
Да, поэтому я хочу иначе сделать.
Спасибо! Вечером буду изучать Ваши советы.
Да, поэтому я хочу иначе сделать.
Спасибо! Вечером буду изучать Ваши советы.
Far behind the skies...
-
- Модератор
- Сообщения: 21281
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Замена текста и символ перехода на новую строку
А зачем Вам sed? Просто уберите первые 3 строки, и в следующей вызывайте tee без опции -a.
Если Вы хотите заменять текст, в котором есть символы новой строки, то тут sed не годится. Юзайте perl (без ключа -p).
Если Вы хотите заменять текст, в котором есть символы новой строки, то тут sed не годится. Юзайте perl (без ключа -p).
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
-
- Сообщения: 201
Re: Замена текста и символ перехода на новую строку
sgfault, Bizdelnick, ага, правильно ли я понял, что символ переноса строки \n может использоваться только на месте bar в случае "sed -e 's/foo/bar/' baz.qux ?
Bizdelnick, ну вот смотрите, что у меня уже есть:
Сюда мне еще нужно будет дописать строки скрипта по-сложнее, например: вставка параметра ядра pcie.aspm=enabled в /etc/default/grub, где-то в конфигах (забыл точно где :) ) для mkinitramfs поставить dep, да и еще с десяток команд найдется.
Ну а зачем мне /n? Хотелось бы отыскать /nexit 0 в rc.local.
//Или как Вы советуете можно удалить с помощь bash и компании сточки в файлах?
sgfault,
Буду дальше разбираться.
Bizdelnick, ну вот смотрите, что у меня уже есть:
Код: Выделить всё
touch /usr/sbin/lowv
echo "echo profile > /sys/class/drm/card0/device/power_method" | tee -a /usr/sbin/lowv
echo "echo low > /sys/class/drm/card0/device/power_profile" | tee -a /usr/sbin/lowv
echo "echo powersave > /sys/module/pcie_aspm/parameters/policy" | tee -a /usr/sbin/lowv
echo "echo powersave > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor" | tee -a /usr/sbin/lowv
echo "echo powersave > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor" | tee -a /usr/sbin/lowv
echo "echo powersave > /sys/devices/system/cpu/cpu2/cpufreq/scaling_governor" | tee -a /usr/sbin/lowv
echo "echo powersave > /sys/devices/system/cpu/cpu3/cpufreq/scaling_governor" | tee -a /usr/sbin/lowv
chmod +x /usr/sbin/lowv
touch /usr/sbin/highv
echo "echo profile > /sys/class/drm/card0/device/power_method" | tee -a /usr/sbin/highv
echo "echo high > /sys/class/drm/card0/device/power_profile" | tee -a /usr/sbin/highv
echo "echo performance > /sys/module/pcie_aspm/parameters/policy" | tee -a /usr/sbin/highv
echo "echo ondemand > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor" | tee -a /usr/sbin/highv
echo "echo ondemand > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor" | tee -a /usr/sbin/highv
echo "echo ondemand > /sys/devices/system/cpu/cpu2/cpufreq/scaling_governor" | tee -a /usr/sbin/highv
echo "echo ondemand > /sys/devices/system/cpu/cpu3/cpufreq/scaling_governor" | tee -a /usr/sbin/highv
chmod +x /usr/sbin/highv
Сюда мне еще нужно будет дописать строки скрипта по-сложнее, например: вставка параметра ядра pcie.aspm=enabled в /etc/default/grub, где-то в конфигах (забыл точно где :) ) для mkinitramfs поставить dep, да и еще с десяток команд найдется.
Ну а зачем мне /n? Хотелось бы отыскать /nexit 0 в rc.local.
//Или как Вы советуете можно удалить с помощь bash и компании сточки в файлах?
sgfault,
Что же касается вашего скрипта, то, может быть, команда c\ - то, что вам надо?
Буду дальше разбираться.
Far behind the skies...
-
- Сообщения: 201
Re: Замена текста и символ перехода на новую строку
Ого! Мне есть что сейчас учить - отложу-ка я рассмотрение команды set - для нее очень много материала нужно обработать.
Может есть, действительно, способ по-проще? Конкретней: нужно дописать команды перед exit 0.
p.s. В sed пробел как обозначать скажите, пожалуйста?
Может есть, действительно, способ по-проще? Конкретней: нужно дописать команды перед exit 0.
p.s. В sed пробел как обозначать скажите, пожалуйста?
Far behind the skies...
-
- Модератор
- Сообщения: 21281
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Замена текста и символ перехода на новую строку
Правильно. sed (как и perl -p) обрабатывает текст построчно, поэтому если foo будет содержать \n, то совпадений не найдётся.
s/^exit 0$/command\nexit 0/
Пробелом, если нужен действительно пробел. Все пробельные символы обозначаются \s.
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
Спасибо сказали:
-
- Сообщения: 201
-
- Модератор
- Сообщения: 4823
- Статус: фанат консоли (=
- ОС: GNU/Debian, RHEL
Re: Замена текста и символ перехода на новую строку
Ну технически всё же можно приаттачить следующую строку, и тогда таки совпадение по \n найдётся, но это уже не совсем тривиально для новичка будет.Bizdelnick писал(а): ↑01.05.2013 23:08sed (как и perl -p) обрабатывает текст построчно, поэтому если foo будет содержать \n, то совпадений не найдётся.
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
The more you believe you don't do mistakes, the more bugs are in your code.
-
- Сообщения: 8735
- Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
- ОС: Slackware-current
Re: Замена текста и символ перехода на новую строку
это как раз элегантно и удобно.
А вот создавать его так как это вы делаете -- криво и косо.
В bash есть специальная фишка для этого: http://www.opennet.ru/docs/RUS/bash_script...ide/c11785.html
А в sed такой фишки нет, и потому надо использовать шаблон, а из него делать новый файл.
-
- Сообщения: 586
- Статус: -
Re: Замена текста и символ перехода на новую строку
Обратите внимание, что в command не должно быть спецсимволов sed, таких как &, \1, \L и тд. Если же они у вас есть, то их надо либо экранировать, либо вообще не использовать sed для этой задачи. Я бы выбрал второе. Без sed файл можно еще разделить, например, csplit-ом.
Вот пример: файл, где есть много exit 0:
Код: Выделить всё
3$ cat 1.tmp
xxx
exit 0
yyy
...
zzz
exit 0
wwww
exit 0
Скрипт (см. комментарии)
Код: Выделить всё
$ cat t.sh
#!/bin/sh
set -euf
# То, что я хочу записать.
content='AAA
BBB
CCC'
# Разделяю файл по /exit 0/. Еще можно попробовать по /^exit 0/, предположив,
# что exit 0 в конце файла всегда будет написан с начала строки.
csplit 1.tmp '/exit 0/' '{*}' >/dev/null
# Сохраняю отсортированный список частей.
l="$(find -maxdepth 1 -type f -name 'xx*' | sort)"
# Нахожу предпоследнюю часть.
f="$(echo "$l" | tail -n2 | head -n1)"
# Дописываю content в конец предпоследней части.
echo "$content" >> "$f"
# Собираю файл назад.
echo "$l" | xargs cat >2.tmp
# Вместо find-а выше можно было использовать и shell globbing, но я его просто
# отключил в самом начале (set -f).
Результат
Код: Выделить всё
$ ./t.sh
$ diff -u 1.tmp 2.tmp
--- 1.tmp 2013-05-02 16:02:15.702889937 +0400
+++ 2.tmp 2013-05-02 16:24:39.431276461 +0400
@@ -5,4 +5,7 @@
zzz
exit 0
wwww
+AAA
+BBB
+CCC
exit 0
Да, и еще: разборку/сборку файла лучше проводить во временной директории (mktemp).
Bizdelnick писал(а): ↑01.05.2013 23:08
Пробелом, если нужен действительно пробел. Все пробельные символы обозначаются \s.
Еще можно так [[:space:]].
Спасибо сказали:
-
- Сообщения: 201
Re: Замена текста и символ перехода на новую строку
Спасибо! Сегодня вечером попробую разобраться.
Правда уже вот назрел вопрос: а что если в файле есть, например, "X11UseLocalhost yes", как сделать, чтобы скрипт не выполнял tee -a "X11UseLocalhost yes" для файла? Можно шаблон?
[off]Я понимаю - это реализуется с помощью if в bash (по ссылке drBatty есть); возможно, много писанины. Если считаете сложным, много текста, то не пишите. :) [off]
Правда уже вот назрел вопрос: а что если в файле есть, например, "X11UseLocalhost yes", как сделать, чтобы скрипт не выполнял tee -a "X11UseLocalhost yes" для файла? Можно шаблон?
[off]Я понимаю - это реализуется с помощью if в bash (по ссылке drBatty есть); возможно, много писанины. Если считаете сложным, много текста, то не пишите. :) [off]
Far behind the skies...
-
- Сообщения: 586
- Статус: -
Re: Замена текста и символ перехода на новую строку
Те, вы хотите проверять каждую добавляемую строку? Мне кажется, это плохая идея. Например, потому, что если строку добавил кто-то другой, ее присутствие не зависит от вашего пакета: этот кто-то ее может удалить, не зная, что ваш пакет на нее полагается. И ваш пакет перестанет работать. Если я правильно понял задачу, то я бы добавлял свой блок в rc.local внутри каких-то особых меток, которые позволяли бы его легко найти:
Код: Выделить всё
##### Start of PKG settings
..ваши настройки..
##### End of PKG settings
Изменение настроек внутри этого блока пользователями тоже нежелательно - если нужно, то можно переопределить настройки дальше в файле. Хотя, тк я пакеты никогда не собирал, может все это и не так.
Тем не менее, последовательность, видимо, все равно имеет значение: если кто-то другой добавит секцию в rc.local после вашего пакета, и она будет изменять те же настройки, то что-то может сломаться.
Что же касается проверки строчек, то, например, если вы сделаете что-нибудь простое типа такого:
Код: Выделить всё
$ cat ./t.sh
#!/bin/sh
set -euf
contents='A A
B B
C
DD'
echo "$contents" | \
xargs -d'\n' sh -euf -c '
for p; do
if ! grep -q -e "$p" 1.tmp; then
echo "$p"
fi
done
' sh
те просто брать строчку и пытаться ее найти в файле, то сломать это будет очень просто. Например, даже на таком файле, в котором просто пробелы расставлены немного "не так", работать скрипт уже будет неправильно:
Код: Выделить всё
$ cat 1.tmp
B B
C C
DDD
$ ./t.sh
A A
B B
C
Как видите, 'B B' надо было выкинуть, и 'C' - возможно тоже, а вот 'DD' надо было оставить. Чтобы этот скрипт улучшить, вам придется каждую строку, которую вы добавляете, превращать в регулярное выражение. Кроме того, если ваша строчка содержит символы, интерпретируемые grep-ом, то их надо еще и экранировать. Одним словом, я бы это делать не стал, тк все еще думаю, что подобрать контр-пример будет все так же просто. Например, допустим вы написали хорошее регулярное выражение, и оно совпало с настройкой в файле (те настройка уже есть). Но что, если эта настройка находится в if, который работает не всегда? Ведь ваше регулряное выражение вряд ли это проверит. Те, мне кажется, что для действительно правильного решения вам нужен парсер баша. Хотя может я и не прав.
Спасибо сказали:
-
- Модератор
- Сообщения: 21281
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Замена текста и символ перехода на новую строку
Это, я так понимаю, речь уже не о rc.local, а о конфиге sshd?
Вообще ИМХО самый верный подход в таких случаях - парсить весь конфиг, вносить необходимые изменения и пересоздавать его полностью. Но можно изобрести костыль типа egrep -qi '^X11UseLocalhost\s+yes$' /etc/ssh/sshd_config || echo "X11UseLocalhost yes" | tee -a /etc/ssh/sshd_config. Естественно, регулярку надо будет доработать, чтобы она соответствовала всем синтаксически верным вариантам записи в конфиге, а это не так-то просто. То есть должно получиться что-то вроде '^\s*X11UseLocalhost\s+"?yes"?\s*$'. Плюс к тому надо будет проверять наличие записи "X11UseLocalhost no".
В данном конкретном случае, поскольку yes - значение по умолчанию для данного параметра, можно просто удалить все строки, в которых определено значение no, и ничего не добавлять: sed -ri '/^\s*X11UseLocalhost\s+"?no"?\s*$/d' /etc/ssh/sshd_config.
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
Спасибо сказали:
-
- Сообщения: 201
Re: Замена текста и символ перехода на новую строку
sgfault, благодарен за скрипт в сообщении №11! Но почему-то у меня вот так с ним получается...
...и не знаю откуда Вы взяли, что я собираю свой пакет. :-) Мне еще до этого далеко, т.к. учусь только программированию (кстати, поэтому я не хочу влезать в bash, потому что Страуструп рекомендует систематически уделять внимание его предмету).
Вобщем, я понял, ув. форумчане, исходя из ваших немного различных аргументаций, что реализация идеи проверки строк будет затратной. Очень вам признателен!
Код: Выделить всё
exit 0
+aaa
+bbb
+exit 0
...и не знаю откуда Вы взяли, что я собираю свой пакет. :-) Мне еще до этого далеко, т.к. учусь только программированию (кстати, поэтому я не хочу влезать в bash, потому что Страуструп рекомендует систематически уделять внимание его предмету).
Вобщем, я понял, ув. форумчане, исходя из ваших немного различных аргументаций, что реализация идеи проверки строк будет затратной. Очень вам признателен!
Far behind the skies...
-
- Сообщения: 586
- Статус: -
Re: Замена текста и символ перехода на новую строку
xoomer писал(а): ↑03.05.2013 20:57sgfault, благодарен за скрипт в сообщении №11! Но почему-то у меня вот так с ним получается...
Код: Выделить всё
exit 0 +aaa +bbb +exit 0
Покажите все полностью: ваши изменения, исходные файлы, запуск команд и их вывод.
Тк в первом сообщении вы упомянули постустановочный скрипт:
-
- Сообщения: 8735
- Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
- ОС: Slackware-current
Re: Замена текста и символ перехода на новую строку
можно НЕ использовать s
-
- Бывший модератор
- Сообщения: 5989
- ОС: OS X, openSuSE, ROSA, Debian
Re: Замена текста и символ перехода на новую строку
Bizdelnick писал(а): ↑01.05.2013 23:08
Правильно. sed (как и perl -p) обрабатывает текст построчно, поэтому если foo будет содержать \n, то совпадений не найдётся.
Для справки(весь топик не читал):
вот так действительно работать не будет:
Код: Выделить всё
diesel@bender-2:~$ echo 'bla' | sed -e 's!bla\n!foo!'
bla
вот так будет:
Код: Выделить всё
diesel@bender-2:~$ echo 'bla' | perl -pe 's!bla\n!foo\n!'
foo
-
- Сообщения: 201
Re: Замена текста и символ перехода на новую строку
sgfault
вот:
Oops! Простите, я что-то тогда напутал! Все отлично работает! :-)
Словом "постустановочный" я обозначил скрипт для выполнения работ после установки ОС.
diesel,
а разве '\n' тому не причина?
вот:
Код: Выделить всё
# То, что я хочу записать.
content='aaa
bbb'
Код: Выделить всё
$ cat 1.tmp
onetwothree
exit 0
Код: Выделить всё
# запускаю скрипт
$ ./sc
Код: Выделить всё
cat 2.tmp
onetwothree
aaa
bbb
exit 0
Oops! Простите, я что-то тогда напутал! Все отлично работает! :-)
Словом "постустановочный" я обозначил скрипт для выполнения работ после установки ОС.
diesel,
(diesel) писал(а):вот так действительно работать не будет:
Код: Выделить всё
diesel@bender-2:~$ echo 'bla' | sed -e 's!bla\n!foo!' bla
а разве '\n' тому не причина?
Код: Выделить всё
drew@5741g-debian:~/tempp$ echo 'bla' | sed -e 's!bla!foo!'
foo
Far behind the skies...
-
- Бывший модератор
- Сообщения: 5989
- ОС: OS X, openSuSE, ROSA, Debian
Re: Замена текста и символ перехода на новую строку
xoomer писал(а): ↑04.05.2013 20:53а разве '\n' тому не причина?
Код: Выделить всё
drew@5741g-debian:~/tempp$ echo 'bla' | sed -e 's!bla!foo!' foo
да, собственно я отвечал на утверждение о том что s/// в sed'е будет работать так же как с perl -p, это не совсем так. perl как раз позволяет "увидеть" \n в первой части s///
Спасибо сказали:
-
- Сообщения: 8735
- Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
- ОС: Slackware-current
Re: Замена текста и символ перехода на новую строку
sed считает СТРОКОЙ последовательность символов до \n. Потому сами \n просто не попадают в буфер sed.
а вот perl и gawk умеют работать и с другими ЗАПИСЯМИ. Не только со строками.
Спасибо сказали: