Идея состоит в том, что эти три строки делают 3 разные вещи, если они вычисляются в стандартной оболочке Bourne (sh), оболочке C (csh) или Perl. Этот хак нужен только в системах, которые не поддерживают указание имени интерпретатора с помощью строки #!
в начале скрипта. Если вы выполняете сценарий Perl, начинающийся с этих трех строк, как сценарий оболочки, оболочка запустит интерпретатор Perl, передав ему имя файла сценария и аргументы командной строки.
В Perl три строки образуют одно утверждение, оканчивающееся ;
, в форме
eval '...' && eval '...' & eval '...' if $running_under_some_shell;
Поскольку скрипт только что начался, $running_under_some_shell
равно undef
, что ложно, и уловки никогда не выполняются. Это неоперация.
Неудобная часть заключается в том, что $?0
анализируется по-разному в sh по сравнению с csh. В sh это означает $?
(состояние выхода последней команды), за которым следует 0. Поскольку предыдущей команды нет, $?
будет 0, поэтому $?0
оценивается как 00
. В csh $?0
- это специальная переменная, которая равна 1, если текущее имя входного файла известно, или 0, если это не так. Поскольку оболочка читает эти строки из скрипта, $?0
будет равно 1.
Следовательно, в sh eval '(exit $?0)'
означает eval '(exit 00)'
, а в csh - eval '(exit 1)'
. Парены указывают, что команда выхода должна быть оценена в подоболочке.
И sh, и csh понимают &&
как «выполнить предыдущую команду, затем выполнять следующую команду, только если предыдущая команда вышла из 0». Так что только sh выполнит eval 'exec perl -wS $0 ${1+"$@"}'
. csh перейдет к следующей строке.
csh будет игнорировать "&" в начале строки. (Я не уверен, что именно это означает для csh. Его цель - сделать это единым выражением с точки зрения Perl.) Затем csh приступает к оценке eval 'exec /usr/bin/perl -wS $0 $argv:q'
.
Эти две командные строки очень похожи. exec perl
означает заменить текущий процесс, запустив копию perl
. -wS
означает то же самое, что и -w
(включить предупреждения) и -S
(ищите указанный скрипт в $PATH
). $0
- имя файла сценария. Наконец, ${1+"$@"}
и $argv:q
создают копию текущих аргументов командной строки (соответственно в sh и csh).
Используется ${1+"$@"}
вместо более обычного "$@"
для обхода ошибки в какой-то древней версии оболочки Bourne. Они имеют в виду одно и то же. Вы можете прочитать подробности в Объяснение Беннетта Тодда (скопировано в ответе Гбэкона).