Как увидеть сообщения о синтаксических ошибках с фактическими номерами строк в родительском скрипте, когда Perl встроен в сценарий оболочки?

#bash #perl #syntax-error #runtime-error #embedded-script

#bash #perl #синтаксическая ошибка #ошибка во время выполнения #встроенный скрипт

Вопрос:

Без какой-либо уважительной причины у меня есть довольно существенный скрипт Perl, встроенный в функцию Bash, которая вызывается в файле autoenv .env .

Это выглядит примерно так:

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

perl -e "$perl" "$inputfile"
  

Я понимаю, что автономные скрипты Perl и PATH переменная — это нечто, и я понимаю, что Term::ANSIColor — это нечто. Речь не об этом.

Мой вопрос в том, что если во встроенном коде Perl есть синтаксическая ошибка, как я могу заставить Perl сообщать фактический номер строки в родительском сценарии оболочки?

Например, скажем, perl= присвоение происходит в строке 120 в этом файле, но в 65-й строке фактического кода Perl есть синтаксическая ошибка. Я понимаю это:

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

… но я хочу видеть это (фактический номер строки в родительском скрипте) вместо этого:

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

То, что я пробовал (это не сработало):

  • присвоение __LINE__
    • даже не знаю, почему я думал, что это сработает; это не переменная, это константа, и вы получаете сообщение об ошибке, указывающее то же самое
  • присвоение $. ( $INPUT_LINE_NUMBER с use English помощью)
    • Я был почти уверен, что это все равно не сработает, потому что это похоже на NR в Awk, и это явно не то, для чего это нужно

Ответ №1:

Как описано в 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"
  

Ответ №2:

На perlrun странице руководства, в разделе для -x , есть этот полезный момент, который «сообщает Perl, что программа встроена в больший фрагмент несвязанного текста, например, в почтовом сообщении».

Все ссылки на номера строк программой (предупреждения, ошибки, …) будут рассматривать #! строку как первую строку. Таким образом, предупреждение во 2-й строке программы, которая находится на 100-й строке в файле, будет отображаться как строка 2, а не как строка 100. Это можно переопределить с помощью #line директивы. (Смотрите Простые старые комментарии (нет!) в perlsyn )

На основе выделенного жирным шрифтом утверждения добавление #line NNN (где NNN — фактический номер строки родительского скрипта, в котором появляется эта директива) достигает желаемого эффекта:

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

Комментарии:

1. Это выводится -e как имя файла. Вы можете передать второй аргумент для #line указания имени файла. Заключите его в двойные кавычки.

2. @ikegami Для начала это был такой запутанный скрипт, что я был полностью согласен с -e , но это отличный совет!