Ваше устройство работает постоянно в течение нескольких минут или есть ли регулярные паузы при передаче?
Если есть паузы, вы можете принудительно пустить буферы и кеш в ядре, чтобы это действие не будет мешать передачам DMA. В качестве альтернативы вы можете настроить ядро на интервал BDFLUSHR
в 1 секунду, чтобы у ядра было меньше данных для записи каждый раз, когда оно решает очистить буферы.
Если вам нужно обеспечить непрерывную работу, вам понадобится ОЗУ с большим количеством каналов, чтобы ЦП и ваше устройство могли одновременно обращаться к памяти (как оказалось, у вас уже есть 4-канальный контроллер памяти). Убедитесь, что вы настроили ОЗУ в автономном режиме , если эта опция доступна. Убедитесь, что вы установили аналогичные модули DRAM в 4 слота, соответствующие каналам памяти, чтобы ваш контроллер памяти действительно мог работать в 4-канальном режиме.
Идея состоит в том, что команда eval
действительна как в оболочке, так и в Perl, с той разницей, что новая строка завершает команду в оболочке, но не в Perl. Вместо этого Perl читает следующую строку, в которой добавляется условие if 0
, фактически отрицающее всю команду.
(Perl поддерживает несколько таких «обратных» структур для сокращений, например. вы можете написать next if $_ == 0
вместо if ($_ == 0) { next }
или print for @a
вместо for (@a) { print }
.)
Если сценарий запускается оболочкой, оболочка обрабатывает eval
и заменяет его интерпретатором Perl, присваивая ему имя сценария($0
)и его аргументы($@
)в качестве параметров.
Затем запускается Perl, читает eval
, пропускает его (из-за if 0
), а затем продолжает выполнение оставшейся части скрипта.
Вот как это должно работать. На практике вы получаете ошибку из-за двух вещей: :1 )Perl читает саму строку hashbang и 2 )способ, которым Linux обрабатывает строки hashbang.
Когда Perl запускает скрипт с хэш-бангом, он воспринимает его не просто как комментарий. Вместо этого он интерпретирует любые параметры Perl, указанные в хэш-банге (, которые вы можете иметь #!/usr/bin/perl -Wln
и т. д. ), но он также проверяет интерпретатор и выполняет его, если сценарий не должен запускаться Perl!
Попробуйте, например. это:
$ cat > hello.sh
#!/bin/bash
echo $BASH_VERSION
$ perl hello.sh
4.4.12(1)-release
Это фактически запускает Bash.
Таким образом, комментарий #perl
должен сказать Perl, что да, на самом деле предполагается, что Perl запускает его, чтобы он не запускал оболочку снова .
Однако,Linux дает все после имени интерпретатора в качестве одного аргумента, поэтому, когда вы запускаете скрипт, он запускается /bin/sh
с двумя аргументами -- # perl, to stop looping
и scriptname.pl
. Первый начинается с тире, но это не совсем --
, поэтому и Dash, и Bash пытаются интерпретировать его как опции. Это неверно, поэтому вы получите сообщение об ошибке, как если бы вы попытались запустить bash ---
или bash "-- #perl"
.
В других системах, которые разделяют аргументы в строке hashbang, -- #perl
выдаст оболочке --
, #perl
и попытается найти файл с именем #perl
. Это снова не сработает. Но, по-видимому, существуют/были некоторые системы, которые принимают знаки #
в качестве маркеров комментариев в строке #!
и/или передают только первый аргумент. (См. страницу Свена Масчека по этому вопросу . )В этих системах это может сработать.
Несколько лучший рабочий вариант приведен вperlrun
(адаптированном):
#!/usr/bin/perl
eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
if $running_under_some_shell;
print("Perl $^V\n");
Запуск этого с bash./script.pl
фактически запускает Perl и печатает (, например.)Perl v5.24.1
.($running_under_some_shell
— это просто неопределенная переменная, которая по умолчанию имеет значение false. if 0
было бы чище, но не так описательно.)
Как сказано в вашей цитате, все это требуется только в старых системах, где #!
не работает должным образом. В некоторых случаях он вообще не поддерживается, и запрос оболочки на запуск двоичного файла, отличного от -, всегда запускает его в оболочке. В других есть ограничение на длину пути в строке hashbang, поэтому #!/really/veeeery/long/path/to/perl
не будет работать.
Просто поместите хэш-банг #!/usr/bin/perl
на любую современную систему.
Самое простое решение, позволяющее избежать ошибки, состоит в том, чтобы иметь только один аргумент для sh
вызова (в некоторых системах ), а также, по-видимому, добавить параметр -x
в вызов perl [d] . И я говорю кажется, потому что это зависит от системы, ядра, оболочки и Perl, используемых для вызова скрипта.
Лучше использовать что-то вроде:
#!/bin/sh --
eval 'exec perl -x -S $0 ${1+"$@"}'
#!/usr/bin/perl
print("Perl $^V\n");
В приведенном выше скрипте единственная выполняемая команда perl — распечатать версию.
Единственная причина использовать что-то подобное объясняется в книге (стр. 21):
Finally, if you are unfortunate enough to be on an ancient Unix system that doesn’t support the magic #! line, or if the path to your interpreter is longer than 32 characters (a built-in limit on many systems), you may be able to work around it......
Это уродливый и запутанный способ замены вызова #!/usr/bin/perl
.
На той же странице 21 находится сценарий, который вы разместили. Следующий сценарий по этой проблеме находится на странице 577 (, продолжайте читать )
.Примечание :Включение perl
имени (слова )в первую строку необходимо только в том случае, если скрипт в любой момент будет вызываться как perl./script
. В этом случае это слово остановит зацикливание Perl. На самом деле второй пример из книги (стр. 577 )— это:
#!/bin/sh -- # -*- perl -*- -p
eval 'exec perl -S $0 ${1+"$@"}'
if 0;
В котором часть комментария(#--perl---p )объясняется в книге как интерпретируемая perl (и по большей части игнорируется ).
Однако предполагается, что вызов оболочки #!/bin/sh
допускает более одного(--
)аргумента. В некоторых системах это не так. Лучше переместить на следующую строку (, если это требуется для emacs ), и/или удалить:
#!/bin/sh -- #
# -*- perl -*- -p
eval 'exec perl -S $0 ${1+"$@"}'
if 0;
Чтобы понять его основы, первое, что нужно понять, это то, что сценарий *может **обрабатываться дважды: один раз оболочкой, а затем интерпретатором, вызываемым оболочкой, в данном случае perl.
Поймите, что скрипт может называться как sh script
, bash./script
, просто как ./script
или,если путь включает текущий рабочий каталог, как script
и даже как /usr/bin/perl script
или как perl script
. В DOS, Unix, Windows, Linux и т. д.
Как сделать так, чтобы вызов perl работал во всех системах?
Этот код (кат./скрипт):
#!/bin/sh --
eval 'exec perl -S $0 ${1+"$@"}'
if 0;
Будет интерпретироваться почти любой оболочкой (, называемой как ./script
или shell./script
следующим образом:
Ядро прочитает первую строку, идентифицирует ее как шебанг и запустит исполняемый файл оболочки, который находится в /bin/sh
файле (или ссылке ). Кроме того, ядро будет принимать и обрабатывать --
как аргумент, означающий «конец опций» [a] [b] . Это строка:
#!/bin/sh --
Оболочка (, предполагающая наличие оболочки в /bin/sh
), прочитает и выполнит первую (не -не закомментированную )строку:
eval 'exec perl -S $0 ${1+"$@"}'
Первое слово (eval )преобразует список аргументов в командную строку для выполнения удаления одного уровня цитирования. То есть он будет преобразован в эту командную строку:
exec perl -S $0 ${1+"$@"}
Первое слово этой (новой )командной строки (, то есть :exec
), сообщит ядру заменить запущенный процесс исполняемым файлом perl
(, искомым в PATH )и аргументами которые являются результатом расширения остальной части командной строки.
Первый аргумент(-S
)указывает Perl также искать исполняемый скрипт, имя которого указано в следующем аргументе($0
). Аргумент $0
— это (обычно )имя ранее загруженного сценария оболочки (, содержащего код, который вы разместили, он же./script
).
Следующий аргумент:${1+"$@"}
означает :, если аргумент $1
существует и не равен нулю,(${1+...}
)замените весь этот аргумент результатом расширения "$@"
. Расширение "$@"
— это список всех аргументов загруженного скрипта.
Вы можете увидеть, какие аргументы задаются в этой командной строке, проверив:
#!/bin/sh -
eval 'exec /usr/bin/printf "<%s> " -S $0 ${1+"$@"}'
Вызов этого скрипта:
$ ./script one two t33 f44 "f55 s66"
<-S> <./script> <one> <two> <t33> <f44> <f55 s66>
Таким образом, эта строка в исходном скрипте будет вызывать perl (эквивалентно )как:
$ perl -S./script one two t33 f44 "f55 s66"
Этот вызов perl заменяет исполняемый сценарий оболочки (exec ).
Затем Perl загружает скрипт и повторно -интерпретирует его содержимое.
Комментарии в Perl также начинаются с#
Таким образом, первая строка (shebang )является комментарием к Perl.
Вторая строка:eval 'exec perl -S $0 ${1+"$@"}'
будет интерпретирована perl (как eval
допустимая команда Perl ), если следующая строка if 0;
, где , а не . Эта третья строка заставляет Perl , а не выполнять вторую строку. Очень длинный способ написания nop
.
Остальная часть сценария затем интерпретируется и выполняется Perl.
Обратите внимание, что вся эта конструкция представляет собой очень сложный способ записи:
#!/usr/bin/perl
Пример "hello world" , аналогичный и использующий параметр perl -x
как , обычно рекомендуемый на сайте perldoc .
Добавление вызова -x к perl гарантирует, что perl сам будет искать #!/usr/bin/perl
шебанг (, который может быть на много строк ниже первой строки ), чтобы начать выполнение скрипта. Это -x
также сделает if 0
излишним.
#!/bin/sh -
eval 'PATH="/usr/bin:/bin:/usr/local/bin:$PATH";: \
;exec perl -x -S -- "$0" ${1+"$@"};#'if 0;
#!/bin/perl -w
# Above is magic header... real Perl code begins here
use strict;
use warnings;
print "hello world!\n";
Это установит более переносимый PATH для поиска исполняемого файла perl. Можно установить больше переменных, чтобы сделать вызов perl более надежным (при необходимости ).
[d] Опция -x
perl будет искать строку shebang с именем perl :#!/bin/perl -w
, чтобы начать интерпретацию скрипта из perl. Это делает разделение между оболочкой и perl более четким.
Этот скрипт будет работать, если он вызывается как:
$./script
hello world!
$ sh./script
hello world!
$ perl./script
hello world!
, но вызовет сбой из оболочки csh
. Это решается добавлением eval '(exit $?0)'
в качестве теста и нового исполняемого файла в виде:
#!/bin/sh --
eval '(exit $?0)' && eval 'PATH="/usr/bin:/bin:/usr/local/bin:$PATH";: \
;exec perl -x -S -- "$0" ${1+"$@"};#'if 0;
exec 'exec perl -x -S -- "$0" $argv:q;#'.q
Волшебный заголовок для запуска Perl-скриптов
Связанное длинное описание.
[a] Вся строка после #!/bin/sh
может интерпретироваться только как один аргумент. В таком случае вся строка -- # perl, to stop looping
может считаться ошибкой. Как если бы bash напрямую загружал скрипт при выполнении ./script
(, в то время как работающей оболочкой является bash ). Подробнее читайте в поиске «Разделение аргументов» .
[b] В очень редких случаях, когда полезно использовать --
Вместо этого более удобно использовать -
, как объяснено в этом вопросе .