使用 sed 管理非常复杂的表达式

使用 sed 管理非常复杂的表达式

我正在尝试编写一个脚本来替换该行:

 [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "

与该行:

# [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "

这将添加新行:

[ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \D{%T} \W]\\$ "

/etc/bashrc文件。基本上,我希望脚本注释旧设置并在提示中的用户名旁边添加时间戳(新设置)。我尝试像这样做第一部分:

pattern=' [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "'
sudo sed 's/${pattern}/#${pattern}/' < /etc/bashrc 

但它不起作用,我认为这是因为字符串中的特殊字符。但我不确定需要转义哪些字符。最后一部分应该是这样的:

sed -i '  [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \D{%T} \W]\\$ "' /etc/bashrc

会给予一些指导。

谢谢

答案1

  1. 脚本中的单引号sed会阻止${pattern}展开。您必须使用双引号(但这会导致提到的特殊字符问题)
  2. 使用sed足够的给定行的寻址来识别它,然后插入注释,如下所示:/^ *\[ *"$PS1 =/s/^/#/
  3. 使用a命令sed追加给定行

在你的情况下,你只想在行中添加一些东西,所以

sed 's/\( *\[ "$PS1" = "..s-..v...$ " \] && PS1="\[[email protected] \)\(.W]..$ "\)/#\1\2\
\1\\D{%T} \2/' /etc/bashrc 

答案2

要使用 sed 进行这种复杂模式的替换:

sed 's/${pattern}/#${pattern}/'

你必须以pattern这种方式强制评估:

sed 's/'${pattern}'/#'${pattern}'/'

在尝试触摸/etc/bashrc和使用之前,请检查该临时文件是否完全达到您想要的效果sudo(此外,在使用之前,sudo您应该检查您是否确实使用了正确的文件,以避免使用假文件)。

答案3

如果您想在没有正则表达式的情况下替换整行,您也可以先获取行号:

LNO=$(grep -FN "$pattern" </etc/bashrc | cut -d':' -f1)

并将该行替换为注释模式和新行:

[ "$LNO" ] \
&& sed -i "${LNO}s/.*/#$pattern\n$newline/" /etc/bashrc

几个月后读起来也会更清楚。

出于测试目的,我总是喜欢先将 sed 写入临时文件(不带 -i 选项),然后重命名它,这样我就不会损害我的配置。

但我还发现此方法不适用于包含 的模式[,],$ and &,这些模式还需要按以下顺序进行一些屏蔽:

pattern=${pattern//\[/\\\[}
pattern=${pattern//\]/\\]}
pattern=${pattern//\$/\\$}
pattern=${pattern//\&/\\&}
pattern=${pattern//\\/\\\\}

这导致以下功能:

#!/bin/bash

declare -a commentAndReplaceMask=('[' ']' '$' '&')
function commentAndReplace () {
  local p="$1"  # pattern
  local s="$p" # sed pattern
  local r="$2"  # replacement
  local f="$3"  # file

  echo args:
  echo p: $p
  echo r: $r
  echo s: $s

  s=${s//\\/\\\\}
  r=${r//\\/\\\\}
  for m in ${commentAndReplaceMask[@]}; do
    s=${s//$m/\\$m}
    r=${r//$m/\\$m}
  done

  echo prepared for sed:
  echo p: $p
  echo r: $r
  echo s: $s

  LNO=$(grep -Fn "$p" <$f | cut -d':' -f1)

  [ "$LNO" ] \
  && sed "${LNO}s/.*/# $s\n$r/" <$f >${f}.tmp

  # mv "${f}.tmp" "$f"
}

commentAndReplace "$@"

相关内容