使用 sed 处理文本块并更改分隔符

使用 sed 处理文本块并更改分隔符

我有一个好奇的问题,我无法弄清楚......

假设我们有一个变量:

_file="/var/log/messages"

并且文件也包含这个块:

/var/log/secure /var/log/messages /var/log/cron /var/log/maillog {
    compress
    monthly
    rotate 6
    create 600
    sharedscripts
    postrotate
        /bin/kill -HUP `cat /var/run/*syslog*.pid 2> /dev/null` 2> /dev/null || true
    endscript
}

我需要一个 sed 命令来选择这个以 $_file 开头并以 } 结尾的特定块,然后在其中执行某些操作......比如说从中删除 $_file。

第一个问题是它的路径,所以我们需要在 sed 中更改分隔符

 sed -e "s|$_file[[:space:]]||" tests_file.txt

上面可以工作,但我需要指定块,通常它应该看起来像:

sed -e "|$_file|,|\}|{s|$_file[[:space:]]||}"

但总是失败:

sed: -e expression #1, char 1: unknown command: `|'

知道发生什么事了吗?

答案1

s可以直接选择分隔符。它可以是

s/a/b/
s|a|b|
sxaxbx

但所选的字符必须是单字节字符。

当将正则表达式指定为地址时,它就不那么简单了:

/regex/
\cregexc

其中c是任意单字节字符。这意味着如果您选择|,则需要在 之前对其进行转义regex,但无需在 之后对其进行转义。

sed -e "\|$_file|,\|\}|{s|$_file[[:space:]]||}" tests_file.txt
#       ^   here  ^

sed它可以与我的 Debian 9 中的GNU 配合使用。


不过你的例子不太恰当。带有 的行$_file总是位于一个块内,s因此总是影响它。这是因为如果你试图把它放在$_file块外面,它将启动一个新的堵塞。

更具教育意义的例子:

sed -e "\|$_file|,\|\}| s|a|X|g" tests_file.txt

这会将块内的每个 更改为aX如果您将包含 的行a放在任何块之外,则不会受到影响。(请注意,我删除了和{。在这个简单的情况下,它们不是必需的。)}s

答案2

_file 变量中的 '/' 使 sed 感到困惑,因为它使用 '/' 作为地址的分隔符以及替代分隔符。
您需要更改分隔符(例如更改为|),从而必须对每个地址的第一个分隔符进行转义(如下所示\|):

sed -e "\|.*$_file .*{$|,\|^}$|s|$_file ||" test_file.txt

相关内容