Продолжаем разбираться с языком программирования Julia. Поскольку для языка, ориентированного на анализ и обработку данных, просто необходимо иметь пакетный режим работы, рассмотрим особенности реализации скриптов на языке Julia и передачи им аргументов из командной строки. Кому-то, может быть, эта тема покажется банальностью, но, учитывая новизну языка, надеюсь, что небольшой обзор способов разбора аргументов командной строки и библиотек для этого, представленных в Julia, всё таки окажется полезным. Для начала, несколько слов о том, как оформляется скрипт. Любой скрипт начинается со строки специального формата, указывающей интерпретатор. Строка начинается с последовательности, известной как шебанг (Shebang). Для Julia такой строкой является: Конечно, можно это и не делать, но тогда придётся запускать скрипт командой: Также, любой скрипт должен завершатьcя символом перевода строки. Это требование стандарта POSIX, которое следует из определения строки как последовательности символов, завершенной символом перевода строки. Для того, чтобы скрипт можно было непосредственно запустить, необходимо наличие у него атрибута executable. Добавить такой атрибут можно в терминале командой: Эти правила справедливы для всех современных операционных систем, кроме, разве что, MS Windows. Перейдём к первому варианту передачи параметров. Аргументы командной строки доступны в Julia-скрипте через константу-массив Base.ARGS. Подготовим простейший скрипт: Этот скрипт просто выводит в консоль тип и содержимое массива ARGS. Очень часто в качестве аргументов командной строки передают имя файла. И здесь есть особенность обработки шаблона файла, передаваемого в качеств аргумента. Например, запустим наш скрипт при помощи команды ./args.jl *.jl и получим: А теперь немного изменим параметр командной строки, окружив маску кавычками:
./args.jl "*.jl". В результате получим: Видим очевидную разницу. В первом случае мы получили массив с именами всех файлов, которые находятся в той же директории. Во втором случае — это лишь та же маска, что была передана в качестве аргумента командной строки. Причина такого различного поведения скрипта заключается в том, что интерпретатор bash (а также близкие к нему), из которого и запускался скрипт, распознаёт шаблоны имён файлов. Подробнее можно найти в поисковике по запросу «Bash Pattern Matching» или «Bash Wildcards». А всё вместе это называется Globs. Среди шаблонов возможно маскирование нескольких символов — *, маскирование одного символа — ?.. Поиск по диапазону [...], И, даже, возможность указать сложные комбинации: Подробнее см. документацию GNU/Linux Command-Line Tools Summary. Если, по какой-то причине, мы не хотим использовать механизм globs, предоставляемый bash, то найти файлы по маске можно уже из скрипта с помощью пакета Globs.jl.
Следующий код преобразует всё, что найдено в строке аргументов, в единый массив имён файлов. То есть, независимо от того, задал ли пользователь маски в кавычках, без кавычек, или просто перечислил имена существующих или несуществующих файлов, в результирующем массиве filelist останутся только имена реально присутствующих файлов или директорий. Эти простые примеры, по сути, и являются демонстрацией использования массива ARGS, где всю логику разбора аргументов реализует программист. Этот подход часто используется тогда, когда набор аргументов чрезвычайно простой. Например перечень имён файлов. Или одна-две опции, которые могут быть обработаны простыми строковыми операциями. Доступ к элементам ARGS осуществляется так же, как и к элементам любого другого массива. Помните только о том, что индекс первого элемента массива в Julia — 1. Является гибким средством описания атрибутов и опций командной строки без необходимости реализации логики разбора.
Воспользуемся немного модифицированным примером из документации пакета — http://carlobaldassi.github.io/ArgParse.jl/stable/ : Если запустить этот скрипт без аргументов, получим вывод справочной информации по их составу: Причём, в квадратных скобках мы видим опциональные аргументы. В то время, как аргумент, отмеченный как arg1 (то есть то, что мы подставим вместо него), является обязательным. Запустим ещё раз, но укажем обязательный атрибут arg1. Мы можем видеть, что parsed_args — это ассоциативный массив, где ключи — имена атрибутов согласно декларации, сделанной в функции parse_commandline, а их значения — то, что было подставлено по-умолчанию или передано в качестве значений аргументов командной строки. Причём значения имеют тот тип, который явно указан при декларации. Декларация аргументов выполняется при помощи макроса @add_arg_table. Возможно декларировать опции : Или аргументы Причем опции могут быть заданы с указанием полной и краткой формы (одновременно --opt2 и -o). Либо, только в единственной форме. Тип указывается в поле arg_type. Значение по-умолчанию может быть задано при помощи default = .... Альтернативой значению по-умолчанию является требование наличия аргумента — required = true.
Возможно задекларировать автоматическое действие, например присваивать true или false в зависимости от наличия или отсутствия аргумента. Это делается с помощью action = :store_true Поле help содержит текст, который будет отображаться в подсказке в командной строке.
Если при запуске мы укажем все атрибуты, то получим: Для отладки из IDE Atom/Juno в первые строки скрипта можно добавить следующий, несколько грязный, но работающий код инициализации массива ARGS. Макрос @__FILE__ — это имя файла, в котором макрос развернут. И это имя для REPL отличается от имени текущего файла программы, полученного через Base.source_path(). Инициализировать константу-массив Base.ARGS другим значением невозможно, но, при этом, можно добавить новые строки, поскольку сам массив не является константой. Массив — это столбец для Julia, поэтому используем vcat(vertical concatenate).  Впрочем, в настройках редактора Juno можно установить аргументы для запуска скрипта. Но их придётся менять каждый раз для каждого отлаживаемого скрипта индивидуально. Этот вариант является реализацией подхода языка разметки docopt — http://docopt.org/. Основная идея этого языка — декларативное описание опций и аргументов в форме, которая может являться и внутренним описанием скрипта. Используется специальный шаблонный язык. Воспользуемся примером из документации к этому пакету https://github.com/docopt/DocOpt.jl Запись doc = ... — это создание Julia-строки doc, в которой содержится вся декларация для docopt. Итогом запуска в командной строке без аргументов будет: Если же воспользуемся подсказкой и попытаемся «создать новый корабль», то получим распечатку ассоциативного массива args, который был сформирован результом разбора командной строки Функция docopt декларируется как: Именованные аргументы help, version, oprtions_first, exit_on_error задают поведение парсера аргументов командрой строки по-умолчанию. Например, при ошибках — завершать выполнение, на запрос версии выдавать подставленное здесь значение version=…, на запрос -h — выдавать справку. options_first используется для указания того, что опции должны находиться до позиционных аргументов. А теперь рассмотрим подробнее этот декларативный язык и реакцию парсера аргументов на введенные значения. Декларация начинается с произвольного текста, который, помимо текста для командной строки, может являться частью документации самого скрипта. Служебное слово «Usage:» декларирует шаблоны вариантов использования данного скрипта. Аргументы декларируются в форме <name>, <x>, <y>. Обратите внимание на то, что в ассоциативном массиве args, который был получен ранее, эти аргументы выступают в роли ключей. Мы использовали форму запуска ./docopt.jl ship new Bystriy, поэтому получили следующие явно инициализированные значения: В соответствии с языком docopt, опциональные элементы задаются в квадратных скобках. Например . В круглых скобках задаются обязательные элементы, но с определенным условием. Например (set|remove) задаёт требование наличия одного из них. Если же элемент указан без скобок, например naval_fate.jl --version, это говорит, что в конкретно этом варианте запуска --version является обязательной опцией. Следующая секция — это секция описания опций. Она начинается со слова «Options:»
Опции декларируются каждая на отдельной строчке. Отступы слева от начала строки важны. Для каждой опции можно указать полную и краткую форму. А также выдаваемое в подсказке описание опции. При этом, опции -h | --help, --version распознаются автоматически. Реакция на них задаётся аргументами функции docopt. Интересной же для рассмотрения является декларация: Здесь форма ...=<kn> задаёт наличие некоторого значения, а  определяет значение по умолчанию. Обратимся опять к значениям, полученным в args: Принципиальным отличием, например, от пакета ArgParse, является то, что значения не типизированы. То есть значение default: 10 выставлено как строка "10".
В отношении же прочих аргументов, которые представлены в args как результат разбора аргументов, следует обратить внимание на их значения: То есть, абсолютно все элементы шаблона, заданные в декларации docopt для всех вариантов использования, представлены в результате разбора с исходными именами. Все опциональные аргументы, которые не присутствовали в командной строке, здесь имеют значение false. Аргументы <x>, <y> также отсутствуют в строке запуска и имеют значение nothing. Прочие же аргументы, для которых совпал шаблон разбора, получили значения true: И уже конкретные значения мы получили для следующих элементов шаблона: Первое значение было задано явно в командной строке как подстановка аргумента , а второе — опция со значением по-умолчанию.
 Также обратите внимание на то, что имя текущего скрипта можно вычислить автоматически.
Например, мы можем вписать: Дополнительной рекоммендацией к размещению парсера аргументов командной строки является его размещение в самом начале файла. Неприятной особенностью Julia в данный момент является довольно долгое подключение модулей. Например using Plots; using DataFrames может отправить скрипт в ожидание на несколько секунд. Это не является проблемой для серверных, однократно загружаемых скриптов, но это будет раздражать пользователей, которые просто хотят посмотреть подсказку по аргументам командной строки. Именно поэтому, сначала надо выдавать справку и проверять аргументы командной строки, а, лишь потом, приступать к загрузке необходимых для работы библиотек. Статья не претендует на полноту рассмотрения всех способов разбора аргументов в Julia. Однако рассмотренные варианты, по сути, покрывают 3 возможных варианта. Полностью ручной разбор массива ARGS. Строго задекларированные, но автоматически разбираемые аргументы в ArgParse. И полностью декларативная, хотя и не строгая форма docopt. Выбор варианта использования полностью зависит от сложности разбираемых аргументов. Вариант с использованием docopt видится наиболее простым в использовании, хотя и требует явного преобразования типов для значений полученных аргументов. Однако, если скрипт не принимает ничего, кроме имени файла, то, вполне, можно воспользоваться выдачей справки по нему при помощи обычной функции println("Run me with file name"), а имена файлов разобрать непосредственно из ARGS так, как это было продемонстрировано в первом разделе.