GNU sed 不会在第 n 次出现时执行操作

GNU sed 不会在第 n 次出现时执行操作

sed 通过 Fedora RPM (dnf)

我需要推进提示文件中的轨道,以便为预间隙添加轨道。 (TRACK 00 不再适用于 shnsplit。)当脚本不起作用时,我使用了命令行。

sed -i 's/TRACK 01/TRACK 02/' *cue

正是我想要的。轨道 01 现在是轨道 02。但是,我现在文件中有两个轨道 02。

sed -i 's/TRACK 02/TRACK 03/2' *cue

绝对什么也不做。我只剩下两个“TRACK 02 AUDIO”列表。

在此输入图像描述

答案1

使用(以前称为 Perl_6)

Raku 是 Perl 编程语言家族中的一种编程语言。我发布此答案是为了强调 Raku 易于阅读的:nth()正则表达式修饰符,它也可以写成:1st:2nd:3rd:4th等。

使用S///运算符:

~$ raku -e 'given slurp() { put S:nth(6)/ line /|*-> line <-*|/ };'  file

#OR

~$ raku -e 'given slurp() { put S:6th/ line /|*-> line <-*|/ };'  file

使用subst()运算符:

~$ raku -e 'put slurp.subst: :nth(6), /line/, "|*-> line <-*|";'  file 

#OR

~$ raku -e 'put slurp.subst: :6th, /line/, "|*-> line <-*|";'  file

输入示例:

1st line Doc
2nd line Sneezy
3rd line Grumpy
4th line Happy
5th line Bashful
6th line Sleepy
7th line Dopey

示例输出(所有代码示例):

1st line Doc
2nd line Sneezy
3rd line Grumpy
4th line Happy
5th line Bashful
6th |*-> line <-*| Sleepy
7th line Dopey

https://docs.raku.org/language/regexes#Positional_adverbs
https://docs.raku.org/routine/subst
https://raku.org

答案2

在尝试解决方案之前,让我们首先分析问题所在。这是你的命令:

sed -i 's/TRACK 02/TRACK 03/2' *cue

不会使用 sed 的 -i 选项,但这是次要问题。sed致力于线,而不是带有文本和正则表达式(如“TRACK 02”)的文件描述了线,不是文件。你的命令说的是:

如果一行包含字符串“TRACK 02”两次(或更频繁),则将第二次出现的字符串更改为“TRACK 03”。像这样:

曲目02曲目02轨道 02 轨道 02 [...] ==>
轨道 02曲目03曲目 02 曲目 02 [...]

另请注意,正则表达式(或者更确切地说,底层常规语法根据定义,它们是上下文无关的。因此,您可以做的事情存在一些限制。了解更多信息是初学者,如果您有兴趣我建议您阅读“Dragon book”(Aho、Sethi 和 Ullman 的《编译器:原理、技术和工具》)进行更深入的分析。

您需要了解的另一件事是 sed 的工作原理:它读取要更改的文本的第一行,然后应用第一个命令,根据结果应用第二个命令,依此类推,直到到达最后一个命令。如果不使用 -n 选项,则打印结果,读入下一行,应用第一个命令,等等,直到最后一个命令应用到最后一行倒数第二个命令的结果- sed 停止。

这就是为什么你不能这样做:

s/TRACK 00/TRACK 01/
s/TRACK 01/TRACK 02/
s/TRACK 02/TRACK 03/
s/TRACK 03/TRACK 04/

这会将“00”更改为“01”,下一个命令会将“01”更改为“02”,下一个“02”更改为“03”,依此类推。最后,所有行都将显示为“TRACK 04”(或者无论您想要列表多长)。

然而,您可以做的是反向进行更改(如果您有超过 10 个标题,请在开头添加类似的行)。当我们这样做时,我们还可以自动添加预间隙TRACK 01:

sed 's/TRACK 09/TRACK 10/
     s/TRACK 08/TRACK 09/
     s/TRACK 07/TRACK 08/
     s/TRACK 06/TRACK 07/
     s/TRACK 05/TRACK 06/
     s/TRACK 04/TRACK 05/
     s/TRACK 03/TRACK 04/
     s/TRACK 02/TRACK 03/
     s/TRACK 01/TRACK 02/
     /FILE/ { a\
TRACK 01
a\
addtional optional text under TRACK 01
        }' /path/to/file
          

最后,这里建议如何使用这个 sed 脚本进行大规模更改。我们将更改后的文件放在其他目录中,而保留原始文件。如果 (除非)我们检查了结果并对结果感到满意,我们将其复制回来覆盖原始结果:

for fWork in "*cue" ; do
     sed 'the script from above' "$fWork" > "/other/path/$fWork"
done

现在,去检查结果。如果你喜欢的话:

mv /other/path/*cur /original/path

相关内容