4

完全没有正当理由,我在一个 Bash 函数中嵌入了一个相当大的 Perl 脚本,该函数在autoenv .env文件中被调用。

它看起来像这样:

perl='
    $inverse = "\e[7m";
    $invoff  = "\e[27m";
    $bold    = "\e[1m";
    ⋮
'

perl -e "$perl" "$inputfile"

我知道独立的 Perl 脚本和PATH变量是一个东西,我知道Term::ANSIColor是一个东西。这不是关于那个。

我的问题是,如果嵌入式 Perl 代码中存在语法错误,如何让 Perl 报告父 shell 脚本中的实际行号?

例如,假设perl=赋值发生在该文件的第 120 行,但实际 Perl 代码的第 65 行存在语法错误。我明白了:

syntax error at -e line 65, near "s/(#.*)$/$comment\1$endcomment/"
Execution of -e aborted due to compilation errors.

…但我想看到这个(父脚本中的实际行号):

syntax error at -e line 185, near "s/(#.*)$/$comment\1$endcomment/"

我尝试过的事情(没有用):

  • 分配给__LINE__
    • 甚至不知道为什么我认为这会起作用;它不是一个变量,它是一个常数,并且你得到一个错误说明
  • 分配给$.( $INPUT_LINE_NUMBERwith use English)
    • 我很确定这无论如何都行不通,因为这就像NR在 Awk 中一样,这显然不是它的用途
4

2 回答 2

9

perlsyn中所述,您可以使用以下指令设置行号和(可选)后续行的文件名:

#line 42 "file.pl"

这意味着您可以使用

#!/bin/sh

perl="#line 4 \"$0\""'
warn("test");
'

perl -e "$perl"

输出:

$ ./a.sh
test at ./a.sh line 4.

使用 时没有避免硬编码行号的干净方法sh,但这是可能的。

#!/bin/sh

script_start=$( perl -ne'if (/^perl=/) { print $.+1; last }' -- "$0" )
perl="#line $script_start \"$0\""'
warn("test");
'

perl -e "$perl"

另一方面,bash提供当前行号。

#!/bin/bash

script_start=$(( LINENO + 2 ))
perl="#line $script_start \"$0\""'
warn("test");
'

perl -e "$perl"
于 2020-09-11T12:38:57.043 回答
4

perlrun在手册页的for 部分-x下有一个有用的花絮,它“告诉 Perl 该程序嵌入在更大的不相关文本块中,例如在邮件消息中。”

程序对行号的所有引用(警告、错误等)都会将该#!行视为第一行。因此,程序第 2 行(文件第 100 行)的警告将报告为第 2 行,而不是第 100 行。这可以通过使用#line指令覆盖。请参阅中的普通旧评论(不是!perlsyn

基于加粗的语句,添加#line NNN(其中NNN是该指令出现的父脚本的实际行号)可以达到预期的效果:

perl='#line 120
    $inverse = "\e[7m";
    $invoff  = "\e[27m";
    $bold    = "\e[1m";
    ⋮
'
⋮
于 2020-09-11T11:32:19.243 回答