解释这个sed条件分支行为

解释这个sed条件分支行为,sed,Sed,我有以下(gnu)sed脚本,用于解析另一个sed脚本,并在单独的一行上输出不同的命令 换句话说,这个脚本应该在每个分号后面加一个换行符,但在匹配或替换命令中的分号除外 Sed脚本: #!/bin/sed -rf # IDEA: # replace ';' by ';\n' except when it's inside a match expression or subst. expression. # Ignored patterns: /^#/b # commented lines

我有以下(gnu)
sed
脚本,用于解析另一个sed脚本,并在单独的一行上输出不同的命令

换句话说,这个脚本应该在每个分号后面加一个换行符
,但在匹配或替换命令中的分号除外

Sed脚本

#!/bin/sed -rf

# IDEA:
# replace ';' by ';\n' except when it's inside a match expression or subst. expression.

# Ignored patterns:
/^#/b   # commented lines
/^$/b   # empty lines
# anything in a single line, without semicolon except at the end
/^[^\n;]*;?$/b

# Processed patterns (put on separate lines):
# Any match preceding a semicolon, or the end of the line, or a substitution
s_/^[^/]+/[^;s]*;?_&\n_;      t printtopline
s/^\\(.)[^\1]+\1[^;s]*;?/&\n/;t printtopline
# Any substitution (TODO)

# Any other command, separated by semicolon
s/\;/\;\n/; t printtopline;

:printtopline
P;D;  # print top line, delete it, start new cycle
例如,我使用以下文件对其进行了测试(实际上改编自@ctac_uuu的一段文字,改为我以前的sed问题):

输入文件:

#!/bin/sed -f

#/^>/N;

:A;
/\n>/!{s/\n/ /;N;bA};  # join next line if not a sequence label
#h;
#s/\(.*\)\n.*/\1/p;
s/^>//g;P

#x;
#s/.*\n//;
D
bA;
s/\;/\;\n/; t printtopline;

:printtopline
$ sed 's/;/;\n/' <<< 'one;two;three;four'
one;
two;three;four
$ sed 's/;/;\n/; P;D;' <<< 'one;two;three;four'
one;
two;
three;
four
输出 上面的脚本生成正确的输出,例如,行
/\n>/!{s/\n/;n;bA};#如果不是序列标签,则连接下一行
变为:

/\n>/!{s/\n/ /;
N;
bA};
  # join next line if not a sequence label
问题: 但是,您能否帮助我理解为什么脚本的这一部分起作用:

#!/bin/sed -f

#/^>/N;

:A;
/\n>/!{s/\n/ /;N;bA};  # join next line if not a sequence label
#h;
#s/\(.*\)\n.*/\1/p;
s/^>//g;P

#x;
#s/.*\n//;
D
bA;
s/\;/\;\n/; t printtopline;

:printtopline
$ sed 's/;/;\n/' <<< 'one;two;three;four'
one;
two;three;four
$ sed 's/;/;\n/; P;D;' <<< 'one;two;three;four'
one;
two;
three;
four

在我看来,分支命令
tprinttopline
在这里是无用的。我想无论替换成功与否,接下来要执行的是
:printtopline

但是,如果我注释掉
t
命令,或者将其替换为
b
,脚本将生成以下输出行:

/\n>/!{s/\n/ /;
N;bA};  # join next line if not a sequence label
info sed
,这里是对
t
的解释:

为什么
t
命令后面紧跟着它的标签
的行为根本不像no命令或
b
命令?

第1部分-p;D序列工作。 比较这两个命令的输出:
sed的/;/\n/”
sed/;/\n/;PD、 "

第一名:

#!/bin/sed -f

#/^>/N;

:A;
/\n>/!{s/\n/ /;N;bA};  # join next line if not a sequence label
#h;
#s/\(.*\)\n.*/\1/p;
s/^>//g;P

#x;
#s/.*\n//;
D
bA;
s/\;/\;\n/; t printtopline;

:printtopline
$ sed 's/;/;\n/' <<< 'one;two;three;four'
one;
two;three;four
$ sed 's/;/;\n/; P;D;' <<< 'one;two;three;four'
one;
two;
three;
four
如果
replaced
标志为true,则执行
t
命令。它正在将此标志更改为
false

case 't': 
    if (replaced)
    {
        replaced = false;
因此,在第一个,
s/\;/\\n/;t印刷背线情况下,替换成功-因此,
replaced
标志设置为true。然后,以下
t
命令正在运行,并将
replaced
标志更改回false

second情况下,不使用
t
command-
s/\;/\\n/,替换也成功-因此,
replaced
标志设置为true

但是现在,该标志被存储到下一个循环,由
D
命令启动。因此,第一个
t
命令出现在新循环中-
s_/^[^/]+/[^;s]*_&\n_;t printtopline
,它检查
替换的
标志,查看标志是否为
,并跳转到标签
:printtopline
,忽略标签前的所有其他命令


模式空间没有换行符,因此
p;D序列只打印模式空间,并用新的输入行开始下一个周期。

关键部分是:

仅当在读取最后一个输入行或执行条件分支后成功进行了替换时,才执行分支到标签

也就是说,
t
回顾过去,并考虑到直到最近一次的所有替换的成功

  • 输入,或
  • 条件分支
考虑一下你正在询问的输入行。在我们所有的替换之后

/\n>/!{s/\n/ /;
N;bA};  # join next line if not a sequence label
当我们到达
p;D
P
命令输出第一行,然后
D
删除第一行并重新启动主循环。现在我们只有

N;bA};  # join next line if not a sequence label
请注意,这并不涉及阅读任何其他行。没有输入发生
D
刚刚删除了部分图案空间

我们将处理剩余的文本(因为其他模式都不匹配,所以不会执行任何操作),直到到达代码的这一部分:

s_/^[^/]+/[^;s]*;?_&\n_;      t printtopline
替换失败(模式空间不包含
/^
)。但是
t
命令不检查仅此
s
命令的状态;它查看自最近的输入或条件分支执行以来所有替换的历史

最近的输入发生在
/\n>/!{s/\n/;n;bA}已读取

最近执行的条件分支为

s/\;/\;\n/; t printtopline;

:printtopline
在代码的原始版本中。此后,没有其他替代成功,因此
t
命令不起任何作用。计划的其余部分按预期继续进行

但在修改后的代码版本中,此时没有条件分支(
b
是无条件分支):

这意味着来自
s_/^[^/]+/[^;s]*;的
t
_&\n_;t printtopline
“查看”了
s/\;/\\n/
成功了,所以它立即跳到
P;D零件。这是什么输出

N;bA};  # join next line if not a sequence label
未经修改


总之:
t
在这里起作用,不是因为它直接跳到标签上,而是因为它作为下一个执行的
t
的动态分隔符。在这里没有
t
,下一个
t

将考虑之前执行的
s
命令,因此,分支到标签在这里并不重要。实际上,我的示例显示了这一点,这就是我想要理解的(省略我认为我得到的
p;D
部分)。@PlasmaBinturong Yes,我只是被我自己的例子迷住了,忘记了你的:)。@PlasmaBinturong我已经更新了答案。请参阅第2部分。我不认为某个特定sed实现的源代码提供了有用的解释。它没有说明为什么用这种方式使用
replaced
,也没有说明将来的版本是否会有所不同。用sed语言解释(参考文档)会更好。@melpomene我认为,两者在连接中都很有用。源代码有助于理解它为何以这种方式工作。主要思想是-存在一些标志(变量、字段、数组的元素-实现细节无关紧要)