Замена переменной PS1 в .bashrc с помощью Sed или Perl - PullRequest
0 голосов
/ 08 февраля 2019

Я пытаюсь заменить строку в файле и сталкиваюсь с проблемами.

Исходный файл:

export PS1='\h:\w\$ '

Команда, которую я выполняю:

perl -pi -e 's~PS1.*~PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]~g' ~/.bashrc

Сообщение об ошибке:

syntax error at -e line 1, near "e["
Execution of -e aborted due to compilation errors.

Я также пробовал sed:

sed -i 's~PS1.*~PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]~g' ~/.bashrc

Результат с Sed:

export PS1="
[e[32;1m][[e[37;1m]@h:[e[37;1m]w[e[32;1m]]\$ [e[0m]

Файл ожидаемого результата:

export PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"

Конечный результат

Это не имеет ничего общего с вопросом, кроме как показать людям, как PS1 будет выглядеть при правильной работе

enter image description here

Ответы [ 3 ]

0 голосов
/ 09 февраля 2019

Просто используйте инструмент, который может работать с литеральными строками, например awk:

$ awk 'BEGIN{new=ARGV[1]; ARGV[1]=""} sub(/PS1=.*/,"PS1="){$0=$0 new} 1' \
    '"\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"' file
export PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"

или, если вы предпочитаете:

$ new='"\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"' \
    awk 'sub(/PS1=.*/,"PS1="){$0=$0 ENVIRON["new"]} 1' file
export PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"

sed не имеет никакого механизма для понимания литеральных строксм. Можно ли надежно избежать метасимволов регулярных выражений с помощью sed для обручей, через которые вам нужно было бы прыгнуть, чтобы заставить sed действовать так, как если бы это было так.

0 голосов
/ 11 февраля 2019

Вы можете сделать это, используя чистый код Bash с:

newps1='"\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"'
readarray -t bashrc_lines <~/.bashrc
printf '%s\n' "${bashrc_lines[@]/PS1=*/PS1=$newps1}" >~/.bashrc

Требуется только заключить в кавычки одинаковые кавычки вокруг точной строки (включая двойные кавычки), которая должна быть помещена справа отPS1=.

Код требует Bash 4 (или 5) для readarray.Он считывает все файлы .bashrc в память, но на практике это не должно быть проблемой.(Если он слишком велик для загрузки в память, он почти наверняка слишком велик, чтобы быть полезным .bashrc.)

См. Замена части строки (BashFAQ / 100 (Как мне сделать строкуманипуляции в bash?)) для получения информации о том, как производится подстановка.

0 голосов
/ 09 февраля 2019

Для sed вы должны экранировать каждую обратную косую черту с другой обратной косой чертой, чтобы они воспринимались буквально.

Команда s дополнительно требует, чтобы вы экранировали разделитель и &, так что это прощеиспользовать команду c, так что удвоение обратной косой черты является единственным требованием:

sed -i '/PS1/c\
export PS1="\\n\\[\\e[32;1m\\][\\[\\e[37;1m\\]\\u@\\h:\\[\\e[37;1m\\]\\w\\[\\e[32;1m\\]]\\\\$ \\[\\e[0m\\]"
' file.txt

Если file.txt содержит:

hello
PS1=foo
world

, то после выполнения этой команды она будет содержать:

hello
export PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"
world
...