使用sed或grep替换行中的子字符串

时间:2012-11-08 12:16:02

标签: shell sed grep

我有一个包含很多行的文件,其中两行是:

videoId: 'S2Rgr6yuuXQ'

var vid_seq=1;

在shell脚本中,我有两个变量, 对于id,值始终为11个字符/数字

ID = 'fsafsferii2'

id_seq = 80

我想用id和id_seq修改这两行

videoId: 'fsafsferii2'

var vid_seq=80;

我用过

sed -i 's/\(videoId: \).*\\1'${id}'/\2' file

但是有错误,我的脚本出了什么问题?

感谢

2 个答案:

答案 0 :(得分:3)

grep命令不会“替换”文本,而是“全局正则表达式打印”。但是sed会。

sed -i'' '/^videoId: /s/: .*/: '"$id"'/;/^var vid_seq=/s/=.*/='"$id_seq"';/'

我不喜欢以这种方式将变量插入到sed脚本中,但是sed很简单,并没有提供实际使用实际变量的机制。如果您要这样做,请在运行此sed脚本之前,对两个变量进行一些格式检查,以确保它们包含您希望它们包含的数据。变量中的意外/会导致sed脚本失败。

每条评论

更新

这是一个成功的测试:

$ id=fsafsferii2
$ id_seq=80
$ cat inp686

videoId: 'S2Rgr6yuuXQ'

var vid_seq=1;

$ sed '/^videoId: /s/: .*/: '"$id"'/;/^var vid_seq=/s/=.*/='"$id_seq"';/' < inp686

videoId: fsafsferii2

var vid_seq=80;

$ 

当然,你需要做一些引用魔术来将单引号引入你的videoId,但我相信你可以自己解决这个问题。

更新2

根据sed的手册页,substitute命令的格式为:

     [2addr]s/regular expression/replacement/flags

[2addr]表示您最多可以指定两个“地址”,可以是行号或正则表达式来匹配。因此s(替换)命令可以在匹配之间采用行,范围,匹配或跨度。在我们的例子中,我们只是使用一个匹配来确定我们想要执行替换的行。

上面的脚本由两个sed命令组成,用分号分隔。

  • /^videoId: / - 匹配以videoId:开头的行...
    • s/: .*/: '"$id"'/; - 使用$id环境变量中的任何内容将冒号中的所有文本替换为行尾。
  • /^var vid_seq=/ - 匹配...... meh,如上所述。
    • s/=.*/='"$id_seq"';/ - 使用$id_seq替换等号中的所有文字。

请注意,'"$id"'构造意味着我们退出单引号,然后立即输入双引号以扩展变量...然后退出双引号并返回一组新的单引号。 Sed脚本在单引号内最安全,因为频繁使用可能由shell解释的字符。

另请注意,因为sed的substitute命令使用正斜杠作为分隔符,所以$id$id_seq变量可能不包含斜杠。如果可能,您可以切换到不同的分隔符。

答案 1 :(得分:1)

有什么问题:

sed -i 's/\(videoId: \).*\\1'${id}'/\2' file
  1. 缺少第三个分隔符(/)。有效语法为s/regex/replace/
  2. 不正确的正则表达式模式(我们假设${id}已被替换)

    \(videoId: \).*\\1fsafsferii2
    

    告诉它匹配一个如下所示的字符串:

    videoId: anything\1fsafsferii2
    

    (正则表达式中的\\与文字反斜杠匹配,因此\\1将匹配文字反斜杠,后跟1而非第一个子表达式

  3. 将匹配的字符串替换为\2

    但由于只有一组括号,\2实际上是空的。

    此外,由于2.中的正则表达式模式与任何内容都不匹配,因此不会替换任何内容。


  4. 这应该有效(GNU sed)

    sed -i 's/\(videoId: \).*/\1 \x27'${id}'\x27/
            s/\(var vid_seq=\).*/\1'${id_seq}'\;/' file
    

    注意:

    • \x27是单引号的十六进制表示(以防止与其他单引号冲突)
    • \;以字面分号表示。如果;未转义,则会将其解释为终止s中的sed命令。