Руководство Perl описывает полностью окольную конструкцию, которая будет работать под любым из csh, sh, или Perl, таких как следующее:
eval '(exit $?0)' && eval 'exec perl -wS $0 ${1+"$@"}'
& eval 'exec /usr/bin/perl -wS $0 $argv:q'
if $running_under_some_shell;
Окольный действительно... кто-то может объяснить подробно, как это работает?
Идея заключается в том, что эти три строки делают 3 разные вещи, если они оцениваются в стандартной оболочке Борна (sh), С-оболочке (csh) или Perl. Этот взлом необходим только в системах, которые не поддерживают указание имени интерпретатора с помощью #!
строка в начале сценария. При выполнении сценария Perl, начинающегося с этих 3 строк в качестве сценария оболочки, оболочка запустит интерпретатор Perl, передав ему имя файла сценария и аргументы командной строки.
В Perl три строки образуют одну инструкцию, завершенную ;
, вида
eval '...' && eval '...' & eval '...' if $running_under_some_shell;
Поскольку сценарий только что запущен, $ running _ under _ some _ shell
является undef
, что является ложным, и evals никогда не выполняются Это не операция.
Изящная часть состоит в том, что $? 0
анализируется по-разному в sh против csh. В sh это означает $?
(состояние выхода последней команды), за которым следует 0. Поскольку предыдущая команда отсутствует, $?
будет 0, поэтому $? 0
вычисляется как 00
. В csh $? 0
является специальной переменной, которая 1, если известно текущее имя входного файла, или 0, если это не так. Поскольку оболочка считывает эти строки из сценария, будет 1 $? 0
.
Поэтому в sh eval '(выход $? 0)'
означает eval '(выход 00)'
, а в csh означает eval '(выход 1)'
. Parens указывает на то, что команда exit должна оцениваться во вложенном корпусе.
Как sh, так и csh понимают & &
, что означает «выполнить предыдущую команду, затем выполнить следующую команду, только если предыдущая команда вышла 0». Так что только sh будет выполнять eval 'exec perl -wS $0 $ {1 + «$ @»}'
. 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 + «$ @»}
вместо более обычного «$ @»
для работы вокруг ошибки в какой-то древней версии оболочки Борна. Они имеют в виду одно и то же. Подробности можно прочитать в пояснении Беннетта Тодда (скопировано в ответ gbacon).
Из коллекции Тома Кристиансена Far More Than Everything You've Ever Wanted to Know About ...:
eval 'exec perl $0 -S ${1+"$@"}'
Newsgroups: comp.lang.tcl,comp.unix.shell
From: bet@ritz.mordor.com (Bennett Todd)
Subject: Re:"$@"
против${1+"$@"}
Followup-To: comp.unix.shell
Date: Tue, 26 Sep 1995 14:35:45 GMT
Message-ID:(Это не совсем вопрос TCL, это вопрос Bourne Shell, поэтому я сделал перепост и установил follow-up-To. перепостил, и установил последующие посты в comp.unix.shell).
Давным-давно (или так гласит история) где-то существовал Bourne Shell. который предлагал два варианта интерполяции всей командной строки. самым простым был
$*
, который просто вставлял все аргументы, теряя все кавычки, которые защищало внутренние пробельные символы. Также предлагалось"$@"
, чтобы защитить пробельные символы. Теперь самое интересное в том, как был реализован"$@"
. В этой ранней оболочке, двухсимвольная последовательность$@
интерполировалась как$1" "$2" "$3" "$4" ... $n
так что когда вы добавляли окружающие кавычки, он завершал цитирование всего шмеру. Мило, мило, слишком мило.... Теперь рассмотрим, что правильное использование
"$@"
расширится до если нет args:
"""
Это пустая строка - единственный аргумент нулевой длины. Это не то же самое, что отсутствие аргументов вообще. Итак, кто-то придумал умное применение другой возможности Bourne Shell, условной интерполяции. The idiom
${varname+value}
расширяется до
value
, если заданоvarname
, и ничего в противном случае. Таким образом обсуждаемая идиома${1+"$@"}
означает ровно то же самое, что и простая
"$@"
без этой древней, чрезвычайно странной ошибки.
Итак, теперь вопрос: какие оболочки имели этот баг? Есть ли какие-нибудь оболочки поставляемые с любой даже смутно недавней ОС, которые включали его?
-- -Bennett bet@mordor.com http://www.mordor.com/bet/