如何解决perl替换中的失败?

How to resolve failures in perl substitutions?

提问人:WGroleau 提问时间:10/25/2023 最后编辑:WGroleau 更新时间:11/4/2023 访问量:143

问:

一个工作了一段时间的脚本最近停止工作,没有任何更改。诊断消息给人的印象是错误在perl中,因为它们引用了不在我的脚本中的代码!perl 可执行文件的日期为 10 月 6 日,大约是我第一次注意到错误的时候。

寻找解决此问题的任何建议。

~/bin/TC是用于清理文本格式的脚本:

#!/bin/zsh

perl -p -i -e 's:\r::g;
               s:(.*):<p>\1</p>:g;
               s:<p></p>::g;
               s:\':’:g;
               s:([\x27"]?[.?!][\x27"]?) :\1  :g;
               s:((”)?[.?!](”)?) :\1  :g;
               s:((’)?[.?!](’)?) :\1  :g;
               s:((»)?[.?!](»)?) :\1  :g;
               s:\*::g;
               s: - :—:g;
               s:- ::g;
               s:([.?!])’” :\1’”  :g;
               s:([.?!])”’ :\1”’  :g;'      $1

以下是最新的调用和结果:

WGroleau@MBP 013 % TC nl_parallel.txt
-i used with no filenames on the command line, reading from STDIN.
Scalar found where operator expected (Missing operator before "$!"?) at -e line 5, near ";}continue{print or die qq(-p destination: $!"
  (Might be a runaway multi-line :: string starting on line 4)
syntax error at -e line 5, near ";}continue{print or die qq(-p destination: $!"
Execution of -e aborted due to compilation errors.
/Users/WGroleau/bin/TC:7: unknown file attribute: ?

显然,命令行上有一个文件名。而且,虽然第四行有一个引号,但它是转义的,所以它实际上没有开始字符串。第五行或任何其他行中没有“继续”。第七行的参考对我来说毫无意义。

当脚本工作时,第四行的引文没有被转义。在显示诊断失败后(在不同的文件上多次),我添加了反斜杠,但它仍然给出相同的消息。

Perl 5,版本 38,Subversion 0 (v5.38.0),为 darwin-thread-multi-2level 构建 macOS 14.0 (23A344)

我没有确切记录错误开始的时间,但大约是在 macOS、perl 和 zsh 更新的几周内——9 月底和 10 月初。

正则表达式 macOS Perl

评论

1赞 tripleee 10/26/2023
你这样做有什么原因吗?它在处理报价的方式上有一些怪癖。zsh
0赞 Håkon Hægland 10/26/2023
若要获取有关错误位置的详细信息,请执行以下操作:尝试从脚本中逐行注释掉,直到错误消息消失。s::
0赞 WGroleau 10/27/2023
@tripleee,zsh 成为 macOS 的默认设置已经有一段时间了。起初我抗拒,但最终还是改了。
0赞 tripleee 10/27/2023
是的,它是默认的交互式 shell;但是,有没有理由不用于这样的简单脚本呢?/bin/sh
0赞 WGroleau 10/30/2023
缺乏细节?失败的确切命令以及确切的诊断消息都在那里。它有一个明确的答案。回答者明显的态度问题不会使答案无效,因为他/她提出的改变确实阻止了错误。

答:

-1赞 ikegami 10/26/2023 #1

\在 shell 单引号文字中并不特别。

#!/bin/sh

# Start of quoted part
#             |
#             v
perl -p -i -e 's:\r::g;
               s:(.*):<p>\1</p>:g;
               s:<p></p>::g;
               s:\':’:g;
#                 ^    ^
#                 |    |
# End of quoted part   End of shell command
               s:([\x27"]?[.?!][\x27"]?) :\1  :g;
               s:((”)?[.?!](”)?) :\1  :g;
               s:((’)?[.?!](’)?) :\1  :g;
               s:((»)?[.?!](»)?) :\1  :g;
               s:\*::g;
               s: - :—:g;
               s:- ::g;
               s:([.?!])’” :\1’”  :g;
               s:([.?!])”’ :\1”’  :g;'      $1
#                                    ^
#                                    |
#           Desired end of quoted part

修复:在 shell 脚本的第六行替换为。\''\''

(请注意,(与之前捕获的文本匹配的正则表达式原子)应该是替换表达式中的(包含之前捕获的文本的变量)。Perl 会警告你这一点。\1$1


有了这个错误,你最终会把以下程序传递给:perl

s:\r::g;
s:(.*):<p>\1</p>:g;
s:<p></p>::g;
s:\:’:g

正如你所看到的,你在第四行有一个未终止的。s:::

但用以下内容包装您的代码:-p

LINE: while (<>) {...;}continue{print or die qq(-p destination: $!\n);}

您原本未终止的 被 终止 应该是一个错误消息。s::::

这解释了令人困惑的错误消息,但它是正确的,因为它是“从第 4 行开始的失控多行 :: 字符串”。

评论

0赞 WGroleau 10/26/2023
有了 1 美元,它按预期工作,谢谢。然而,无论是现在还是以前,都没有关于 \1 的警告,它的工作原理与 1 美元相同。此外,在前几个月,它使用 ' 而不是 \' 或 '\'''\''
0赞 WGroleau 10/26/2023
在将近一年的时间里,它一直有效。当它停止工作时,我将其更改为也不起作用。它从来都不是,它是 zsh 脚本中的 perl 程序。s:':’:g;s:\':’:g;s:\:’:g;
0赞 WGroleau 10/26/2023
直到最近,它确实运行良好。由于失败,我添加了\,但尝试的修复没有帮助。