2

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

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

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

谢谢

4

2 回答 2

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 的手册页,替代命令的格式为:

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

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

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

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

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

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

于 2012-11-08T12:33:28.167 回答
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. 中的正则表达式模式不匹配任何内容,因此没有任何内容被替换。


这应该有效(GNU sed)

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

笔记:

  • \x27是单引号的十六进制表示(防止与另一个单引号发生冲突)
  • \;对于文字分号。如果;未转义,则将其解释为s终止sed.
于 2012-11-09T10:42:53.157 回答