Как увидеть синтаксические ошибки, сообщаемые с фактическими номерами строк в родительском сценарии, когда 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/(#.*)$/$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_NUMBER с участием use English)
    • Я был почти уверен, что это все равно не сработает, потому что это похоже на NR в Awk, и явно не для этого

2 ответа

Решение

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

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

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

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

perl='#line 120
    $inverse = "\e[7m";
    $invoff  = "\e[27m";
    $bold    = "\e[1m";
    ⋮
'
⋮
Другие вопросы по тегам