LINUX.ORG.RU

Как в файле найти и заменить строку с кучей спецсимволов?

 , ,


0

1

Пример.
Файл: /etc/skel/.bashrc.
Строка: PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
требуется заменить на подобную.
Пытался с помощью sed. Взять все в одинарные кавычки не помогает. Не хотелось бы экранировать каждый спецсимвол (но у меня и не получилось вот так сразу). Можно через замену всего файла (cat <<'EOF' > /etc/skel/.bashrc), но это слишком избыточно из за одной строки.


Как насчёт не париться со спецсимволами и заменить целиком строки начинающиеся на PS1=? Там эти спецсимволы не такие простые как кажется, к примеру \033 это восьмеричное представление байта \x1b.

neumond
()
$ cat replace.pl
#!/usr/bin/perl -p
$p = quotemeta '${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$';
s/$p/abcd/;
$ cat tmp
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
$ cat tmp | ./replace.pl 
PS1='abcd '

Пояснение: сделать такую замену однострочником будет проблематично, так как экранирование спецсимволов нужно не только для процессора, выполняющего замену (sed, perl, …), но и для самого шелла.

annulen ★★★★★
()
Последнее исправление: annulen (всего исправлений: 1)
Ответ на: комментарий от mnwest

Для замены на строку с спецсимволами нужно аналогично определить вторую переменную, например, $v, и вместо s/$p/abcd/ написать s/$p/$v/

Работает эта штука примерно как sed, меняет любое количество вхождений $p в файле на $v. Если нужно несколько раз заменять в пределах строки, то пишем s/$p/$v/g (как с седом)

annulen ★★★★★
()
Последнее исправление: annulen (всего исправлений: 1)
$ cat tmp
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

sed:

$ sed "s/'[^']*'/'test line '/" tmp
PS1='test line '

awk:

$ awk -F"'" '{OFS="'\''"; $2="test line "; print $0}' tmp
PS1='test line '
iron ★★★★★
()
cat входной-файл.txt | xxd -ps | tr -d '\n' | sed s/$(cat файл-что-менять.txt | xxd -ps | tr -d '\n')/$(cat файл-на-что-менять.txt | xxd -ps | tr -d '\n')/g | xxd -r -ps

содержимое файлов *.txt — произвольное (многострочный текст, бинарные данные, …)

замена текста (НЕ регэкспы)

futurama ★★★★★
()

Можно через замену всего файла

Ты уверен что можно? Может быть, конечно, у тебя какая-то особенная ситуация, но вообще всегда желательно менять только то что хочешь поменять, и не трогать остальное, даже если тебе прямо сейчас кажется что ты точно знаешь его содержимое. Когда-нить потом оно может измениться и твоя заменялка будет его портить.

firkax ★★★★★
()
Ответ на: комментарий от neumond

Да нет, спецсмвол в указанном тобой фрагменте это обратный слэш. А \033 - это уже последовательность, которая парсится шеллом, и заменялке на неё плевать.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Можно через замену всего файла

Ты уверен что можно?

Уверен, и написал как это можно сделать (с помощью конструкции <<'EOF' в скрипте). В остальном полностью с тобой согласен, просто это единственный способ на тот момент который работал. Зато теперь есть выбор!

mnwest
() автор топика
Ответ на: комментарий от annulen

Пояснение: сделать такую замену однострочником будет проблематично, так как экранирование спецсимволов нужно не только для процессора, выполняющего замену (sed, perl, …), но и для самого шелла.

Говно вопрос.

$ cat ps1.txt 
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

$ perl -p -e 'BEGIN { $p = '\''${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$'\'';}' -e 's/\Q$p\E/xxx/' ./ps1.txt 
PS1='xxx '
debugger ★★★★★
()
Ответ на: комментарий от debugger

Тогда уж лучше вот так:

perl -p -e 'BEGIN { $p = q"${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$"}' -e 's/\Q$p\E/xxx/' tmp

в предположении, что внутри искомой строки нет двойных кавычек. Но всё равно читаемость так себе.

annulen ★★★★★
()