如何用sed/awk/perl替换.bashrc中PS1变量或采用/etc/profile.d方案
编辑 - 2023年6月8日 - 原问题基本保留
感谢Charles Duffy在评论中提供的宝贵反馈。原问题对应第1项,但根据反馈,第2项是管理系统运维任务的更佳方案。完成perl和/etc/profile.d的研究后,我可能会提出新问题或在此补充相关内容。
- 原问题:如何使用
sed、awk或perl在文件中搜索并替换字面字符串,例如.bashrc文件中的PS1=<string>? - 更佳问题:如何利用存储在
/etc/profile.d中的脚本,实现用户登录时自动启用所需的提示符行为?
目标
在Debian电脑和DietPi(ARM)Linux系统中自动化自定义bash提示符。自定义提示符会插入空行分隔命令与终端输出,样式如下(颜色不同):
root@dpiBox /root # user@dpiBox /home/user $
其中root@dpiBox为红色;user@dpiBox为绿色;当前工作目录始终显示为蓝色。
背景
创建新user时,/etc/skel/.bashrc的副本会被放入用户主目录,命名为/home/user/.bashrc。root用户已有/root/.bashrc副本。
我最初的计划是在添加新用户前通过脚本编辑/etc/skel/.bashrc,并手动编辑/root/.bashrc。但root或任何用户登录时,/etc/profile.d下正确部署的脚本会自动执行。Charles Duffy建议使用此功能以更好地管理系统运维任务!
默认.bashrc相关内容
/etc/skel/.bashrc、/root/.bashrc和/home/user/.bashrc中的默认相关行:
# /root/bashtest (模拟默认.bashrc) # /etc/skel/.bashrc # /root/.bashrc # /home/user/.bashrc #force_color_prompt=yes if [ "$color_prompt" = yes ]; then PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' else PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' fi
自定义步骤
步骤1 - 开启彩色提示符
取消注释以下行:
force_color_prompt=yes
步骤2 - 替换PS1自定义提示符
将旧PS1:
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
替换为新PS1:
PS1='${debian_chroot:+($debian_chroot)}\n\[\033[01;32m\]\u@\h\[\033[00m\]\[\033[01;34m\] $(pwd -P) \[\033[00m\]\n\$ '
- 对于
/home/user/.bashrc,[01;32m\]对应绿色; - 对于
/root/.bashrc,需将此代码改为[01;31m\](红色)。
工具尝试情况
步骤1 - sed:效果良好
开发脚本/usr/local/bin/bashsed(用于编辑bashtest/.bashrc):
#!/bin/bash # 取消注释以强制开启彩色提示符 off="#force_color_prompt=yes" on="force_color_prompt=yes" sed -i "s|$off|$on|" /root/bashtest
定义on和off时使用双引号或单引号均可,但sed命令必须使用双引号。
步骤1 - perl:效果良好
开发脚本/usr/local/bin/bashperl(用于编辑bashtest/.bashrc):
#!/bin/bash # 取消注释以强制开启彩色提示符 perl -i.bak -pe 's/#force_color_prompt=yes/force_color_prompt=yes/' /root/bashtest
i.bak选项会先将/root/bashtest备份为/root/bashtest.bak,再就地编辑文件。此命令可直接在命令行使用,无需i.bak选项。
步骤2 - sed:效果不佳
开发脚本/usr/local/bin/bashsed(用于编辑bashtest/.bashrc):
#!/bin/bash # 替换旧PS1为新PS1 # old \[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\ # PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' old='\\[\\033\[01;32m\\]\\u@\\h\\[\\033[00m\\]:\\[\\033\[01;34m\\]\\w\\[\\033\[00m\\]\\' # new \n\[\033[01;32m\]\u@\h\[\033[00m\]\[\033[01;34m\] $(pwd -P) \[\033[00m\]\n\ # PS1='${debian_chroot:+($debian_chroot)}\n\[\033[01;32m\]\u@\h\[\033[00m\]\[\033[01;34m\] $(pwd -P) \[\033[00m\]\n\$ ' new='\\n\\[\\033\[01;32m\\]\\u@\\h\\[\\033\[00m\\]\\[\\033\[01;34m\\] \$(pwd -P) \\[\\033\[00m\\]\\n\\' sed -i "s|$old|$new|" /root/bashtest
- 使用双引号定义
old和new时,脚本运行无报错但无替换效果; - 使用单引号定义时,脚本抛出错误:
sed: -e expression #1, char 149: unterminateds' command`。
编辑 - 2023年6月8日 - 评论
我已发布使用bash脚本调用perl实现步骤2的解决方案。
根据Charles Duffy的反馈,步骤2的perl解决方案可修改为使用存储为bash环境变量的字面字符串。
Charles Duffy建议将脚本放在/etc/profile.d中,让用户登录时自动运行,以更好地管理运维任务,我需要进一步研究理解该方案。
原问题相关背景
我已广泛搜索并进行了数十次实验,但仍无法解决sed替换PS1的问题,需要排查我的sed代码!我也可以接受使用awk,但需要先看到简单的命令结构,再插入字面字符串,否则容易搞混语法。
内容的提问来源于stack exchange,提问作者SystemTheory

