Замена текста и символ перехода на новую строку

На самом деле это единственный раздел про unix на этом форуме

Модераторы: /dev/random, Модераторы разделов

Аватара пользователя
xoomer
Сообщения: 201

Замена текста и символ перехода на новую строку

Сообщение xoomer »

Здравствуйте.
Чтобы создать постустановочный скрипт мне необходима ваша помощь.
Вместо того, чтобы делать:
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...
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: Замена текста и символ перехода на новую строку

Сообщение sgfault »

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".

Но ведь в вашем примере вы ничего не заменяете, а просто стираете все, что было и создаете новый файл.

xoomer писал(а):
01.05.2013 15:44
Не пойму - как быть со символами переноса строки в sed?

А что с ними? Они могут быть в 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


Спасибо сказали:
Аватара пользователя
xoomer
Сообщения: 201

Re: Замена текста и символ перехода на новую строку

Сообщение xoomer »

> Но ведь в вашем примере вы ничего не заменяете, а просто стираете все, что было и создаете новый файл.
Да, поэтому я хочу иначе сделать.
Спасибо! Вечером буду изучать Ваши советы.
Far behind the skies...
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21281
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Замена текста и символ перехода на новую строку

Сообщение Bizdelnick »

А зачем Вам sed? Просто уберите первые 3 строки, и в следующей вызывайте tee без опции -a.
Если Вы хотите заменять текст, в котором есть символы новой строки, то тут sed не годится. Юзайте perl (без ключа -p).
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
xoomer
Сообщения: 201

Re: Замена текста и символ перехода на новую строку

Сообщение xoomer »

sgfault, Bizdelnick, ага, правильно ли я понял, что символ переноса строки \n может использоваться только на месте bar в случае "sed -e 's/foo/bar/' baz.qux ?

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...
Спасибо сказали:
Аватара пользователя
xoomer
Сообщения: 201

Re: Замена текста и символ перехода на новую строку

Сообщение xoomer »

Ого! Мне есть что сейчас учить - отложу-ка я рассмотрение команды set - для нее очень много материала нужно обработать.
Может есть, действительно, способ по-проще? Конкретней: нужно дописать команды перед exit 0.

p.s. В sed пробел как обозначать скажите, пожалуйста?
Far behind the skies...
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21281
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Замена текста и символ перехода на новую строку

Сообщение Bizdelnick »

xoomer писал(а):
01.05.2013 22:39
правильно ли я понял, что ASCII-символ переноса строки \n может использоваться только на месте bar в случае "sed -e 's/foo/bar/' baz.qux ?

Правильно. sed (как и perl -p) обрабатывает текст построчно, поэтому если foo будет содержать \n, то совпадений не найдётся.

xoomer писал(а):
01.05.2013 22:52
нужно дописать команды перед exit 0

s/^exit 0$/command\nexit 0/

xoomer писал(а):
01.05.2013 22:52
В sed пробел как обозначать скажите, пожалуйста?

Пробелом, если нужен действительно пробел. Все пробельные символы обозначаются \s.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
xoomer
Сообщения: 201

Re: Замена текста и символ перехода на новую строку

Сообщение xoomer »

Спасибо!)
Far behind the skies...
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4823
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: Замена текста и символ перехода на новую строку

Сообщение SLEDopit »

Bizdelnick писал(а):
01.05.2013 23:08
sed (как и perl -p) обрабатывает текст построчно, поэтому если foo будет содержать \n, то совпадений не найдётся.
Ну технически всё же можно приаттачить следующую строку, и тогда таки совпадение по \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.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Замена текста и символ перехода на новую строку

Сообщение drBatty »

xoomer писал(а):
01.05.2013 15:44
Не пойму - как быть со символами переноса строки в sed?

xoomer писал(а):
01.05.2013 15:44
Т.к., мне кажется, удалять rc.local и заново его создавать не есть элегантно?

это как раз элегантно и удобно.

А вот создавать его так как это вы делаете -- криво и косо.

В bash есть специальная фишка для этого: http://www.opennet.ru/docs/RUS/bash_script...ide/c11785.html

А в sed такой фишки нет, и потому надо использовать шаблон, а из него делать новый файл.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: Замена текста и символ перехода на новую строку

Сообщение sgfault »

Bizdelnick писал(а):
01.05.2013 23:08
xoomer писал(а):
01.05.2013 22:52
нужно дописать команды перед exit 0

s/^exit 0$/command\nexit 0/

Обратите внимание, что в 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
xoomer писал(а):
01.05.2013 22:52
В sed пробел как обозначать скажите, пожалуйста?

Пробелом, если нужен действительно пробел. Все пробельные символы обозначаются \s.

Еще можно так [[:space:]].
Спасибо сказали:
Аватара пользователя
xoomer
Сообщения: 201

Re: Замена текста и символ перехода на новую строку

Сообщение xoomer »

Спасибо! Сегодня вечером попробую разобраться.

Правда уже вот назрел вопрос: а что если в файле есть, например, "X11UseLocalhost yes", как сделать, чтобы скрипт не выполнял tee -a "X11UseLocalhost yes" для файла? Можно шаблон?

[off]Я понимаю - это реализуется с помощью if в bash (по ссылке drBatty есть); возможно, много писанины. Если считаете сложным, много текста, то не пишите. :) [off]
Far behind the skies...
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: Замена текста и символ перехода на новую строку

Сообщение sgfault »

xoomer писал(а):
03.05.2013 16:22
Правда уже вот назрел вопрос: а что если в файле есть, например, "X11UseLocalhost yes", как сделать, чтобы скрипт не выполнял tee -a "X11UseLocalhost yes" для файла? Можно шаблон?

Те, вы хотите проверять каждую добавляемую строку? Мне кажется, это плохая идея. Например, потому, что если строку добавил кто-то другой, ее присутствие не зависит от вашего пакета: этот кто-то ее может удалить, не зная, что ваш пакет на нее полагается. И ваш пакет перестанет работать. Если я правильно понял задачу, то я бы добавлял свой блок в 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, который работает не всегда? Ведь ваше регулряное выражение вряд ли это проверит. Те, мне кажется, что для действительно правильного решения вам нужен парсер баша. Хотя может я и не прав.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21281
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Замена текста и символ перехода на новую строку

Сообщение Bizdelnick »

xoomer писал(а):
03.05.2013 16:22
Правда уже вот назрел вопрос: а что если в файле есть, например, "X11UseLocalhost yes", как сделать, чтобы скрипт не выполнял tee -a "X11UseLocalhost yes" для файла? Можно шаблон?

Это, я так понимаю, речь уже не о 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.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
xoomer
Сообщения: 201

Re: Замена текста и символ перехода на новую строку

Сообщение xoomer »

sgfault, благодарен за скрипт в сообщении №11! Но почему-то у меня вот так с ним получается...

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

 exit 0
+aaa
+bbb
+exit 0


...и не знаю откуда Вы взяли, что я собираю свой пакет. :-) Мне еще до этого далеко, т.к. учусь только программированию (кстати, поэтому я не хочу влезать в bash, потому что Страуструп рекомендует систематически уделять внимание его предмету).

Вобщем, я понял, ув. форумчане, исходя из ваших немного различных аргументаций, что реализация идеи проверки строк будет затратной. Очень вам признателен!
Far behind the skies...
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: Замена текста и символ перехода на новую строку

Сообщение sgfault »

xoomer писал(а):
03.05.2013 20:57
sgfault, благодарен за скрипт в сообщении №11! Но почему-то у меня вот так с ним получается...

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

 exit 0
+aaa
+bbb
+exit 0

Покажите все полностью: ваши изменения, исходные файлы, запуск команд и их вывод.

xoomer писал(а):
03.05.2013 20:57
...и не знаю откуда Вы взяли, что я собираю свой пакет. :-)

Тк в первом сообщении вы упомянули постустановочный скрипт:
xoomer писал(а):
01.05.2013 15:44
Чтобы создать постустановочный скрипт мне необходима ваша помощь.

Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Замена текста и символ перехода на новую строку

Сообщение drBatty »

sgfault писал(а):
02.05.2013 16:30
Обратите внимание, что в command не должно быть спецсимволов sed, таких как &, \1, \L и тд

можно НЕ использовать s
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
diesel
Бывший модератор
Сообщения: 5989
ОС: OS X, openSuSE, ROSA, Debian

Re: Замена текста и символ перехода на новую строку

Сообщение diesel »

Bizdelnick писал(а):
01.05.2013 23:08
xoomer писал(а):
01.05.2013 22:39
правильно ли я понял, что ASCII-символ переноса строки \n может использоваться только на месте bar в случае "sed -e 's/foo/bar/' baz.qux ?

Правильно. 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
Спасибо сказали:
Аватара пользователя
xoomer
Сообщения: 201

Re: Замена текста и символ перехода на новую строку

Сообщение xoomer »

sgfault
вот:

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

# То, что я хочу записать.
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...
Спасибо сказали:
Аватара пользователя
diesel
Бывший модератор
Сообщения: 5989
ОС: OS X, openSuSE, ROSA, Debian

Re: Замена текста и символ перехода на новую строку

Сообщение diesel »

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///
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Замена текста и символ перехода на новую строку

Сообщение drBatty »

xoomer писал(а):
04.05.2013 20:53
а разве '\n' тому не причина?

sed считает СТРОКОЙ последовательность символов до \n. Потому сами \n просто не попадают в буфер sed.

а вот perl и gawk умеют работать и с другими ЗАПИСЯМИ. Не только со строками.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали: