Чего же мне хотелось от жизни?
Независимо от методик, преподавателей и пристрастий, изучение английского языка начинается с очень важного базового процесса, который впоследствии уходит в фоновый режим, становится менее приоритетным, но не прекращается довольно долго (в идеальном случае бесконечно развивающегося человека в вакууме – никогда). И это не что иное, как пополнение своего лексикона новыми словами иностранного языка. Запоминание пар (слово/перевод) каждый организует по-своему, но чаще всего оно базируется на повторении. Самый простой и достаточно хороший способ – карточки, на одной стороне которых написано слово, а на другой – неожиданно – его перевод.
While (not колода пуста && not надоело) do { Взял случайную карточку Посмотрел слово Предложил перевод Перевернул карточку Сравнил перевод с эталоном If (перевод совпал с эталоном) && (слово в зубах навязло) удалил карточку из колоды }
Читая документацию на английском, я неожиданно поймал себя на мысли, что в таких карточках очень нуждаюсь. Ибо слишком часто я сталкивался со следующим сценарием: встреченное неизвестное слово ищется в словаре, после чего мозг не утруждая себя лишними усилиями, сохраняет его в кеше, встраивает в контекст предложения, считывает получившееся предложение, делает некоторые умозаключения, после чего умозаключения сохраняет в ПЗУ, а все остальное стирает за ненадобностью. После третьего захода в словарь из-за одного и того же слова я понял, что пора вспомнить школьные годы и попрактиковаться в выписывании/запоминании новых слов.
В наш век карточкам уже не место, а вот скрипты для таких целей самое то. Остановить свой выбор именно на bat-никах меня заставило банальное желание поразвлечься. Ибо с такими инструментами даже самые простые задачи иногда оказываются очень интересными.
Дизайн наше всё
Итоговое использование скрипта я видел следующим образом: в консоли в любой момент можно набрать dict [command [params] ], что в зависимости от команды:
- <пустая команда> или show_random
выведет случайное иностранное слово, а после нажатия любой клавиши дополнит его переводом; add hello habr:приветствую, о Хабр/привет всем на хабре
добавит в список карточек соответствующую запись(английская фраза: перевод1/перевод2/перевод3/...);- show_all
отобразит все слова с их переводами - show hello habr
Отобразит конкретную запись и ее перевод - show 23
Аналогично show_random, но отображается не случайная запись, а с указанным номером - show_contents
Выведет пронумерованный список слов, не показывая переводы - remove_last или rml
Удалит последнее добавленное слово - remove 13 или remove hello habr (можно сокращать до rm
-rf /*13)
Удалит тринадцатую по счету запись или же запись с указанной фразой соответственно.
Как реализовать вызов скрипта в любой момент и ежу понятно: засунуть dict.bat в любую папку, прописанную в переменной PATH. А вот весь остальной функционал некоторых людей слегка пугает. Всё дело в том, что батники издревле считаются филиалом ада на земле, где до некоторого времени банальное ветвление нужно было организовывать при помощи оператора безусловного перехода (поскольку в блоке then изначально поддерживалась только одна команда). Но всё течет и меняется, возможности cmd уже давно позволяют имитировать написание функций, что существенно расширяет наши перспективы. А делается это так:
call :myFunction %param1% %param2% %param3% …
…
:myFunction
echo Hello, Habr!
exit /b
Для возвращения результатов работы можно пользоваться «глобальными» переменными, но для тонких ценителей есть более интересное решение – засовывать результат в код возврата. Впрочем, чаще всего это всё равно требует использование переменной, однако спасает от необходимости помнить ее имя. Маленький пример:
@echo off
call :Answer_to_the_Ultimate_Question_of_Life_the_Universe_and_Everything
echo %errorlevel%
exit /b
:Answer_to_the_Ultimate_Question_of_Life_the_Universe_and_Everything
set SIX=1+5
set NINE=8+1
set /a ANSWER=%SIX%*%NINE%
exit /b %ANSWER%
Тяжела и неказиста жизнь дурного программиста
Но вернемся к изначальному скрипту. Функция add в нулевом приближении была проста до безумия – она запихивала получаемую в качестве параметра строку в файл vocabulary:
echo %* >> vocabulary || exit /b 1
Однако для такой операции мы должны находиться в каталоге со скриптом, а не в каталоге из которого скрипт был вызван. Для этого есть пара важных трюков: во-первых, этот каталог можно узнать при помощи нулевого параметра скрипта (%0) с нужными модификаторами и кавычками на случай неожиданных пробелов(“%~dp0”). Но даже зная его, мы не можем выполнить банальное cd “%~dp0”, т. к. команда даст нежелательный результат в случае а) расположения скрипта на другом жестком диске (попробуйте сделать cd D:\temp находясь на C:\, будете приятно удивлены), либо б) расположения скрипта на сетевом ресурсе. К счастью, оба случая нивелируются уличной магией команды pushd “%~dp0”.
Казалось бы, теперь уже можно выдохнуть спокойно: первая и самая простая функция написана, можно переходить к более сложным ее собратьям. Ан нет, подводные камни еще остались. Но для их объяснения я должен задать весьма странный вопрос: а вам слабо вывести на экран консоли слово ON без помощи дополнительных временных файлов и ручного ввода пользователя? Одним батником банальное слово ON на черном экране? Вы попробуйте, попробуйте, я здесь подожду.
…
Забавно, не так ли? Я знаю только один способ это сделать: функцию « echo. », переводящую курсор на следующую строку, можно вызвать с параметрами. Конструкция «echo.ON» всё-таки выполнит эту сложнейшую для cmd задачу. Собственно, к чему это я? Случайный вызов dict add без параметров развлечет вас очень странной новой записью, если к echo не добавить точку. Впрочем, доработка напильником добавила минимальную проверку на корректность вводимой строки, что отмело подобные выходки. Но в других областях этого скрипта эта проблема и ее решение полностью сохраняются. Советую во всех случаях вывода сообщений использовать только echo. как более предсказуемую.
Функция show_all реализуется элементарно: при помощи цикла for с ключом /f она пробегает по vocabulary и каждую строку отдает парсеру, который выводит ее с нужным форматированием используя аналогичный цикл. Всё это скучно. А вот вывод записи по ее номеру, что крайне нужно самой востребованной функции show_random, воплощать было несколько любопытнее. Выдрать из текстового файла определенную строку средствами cmd, казалось, будет сложно. Но решение оказалось вполне себе простым и доступным, только для его обнаружения нужно было хорошо знать возможности утилиты findstr. А именно, нас интересует нумерация строк в результатах поиска: производим поиск по маске «все возможные строки» (.*) с ключом /n (нумерация), получаем фактически нумерованный файл vocabulary, результат засовываем в цикл for, выдираем пары (номер строки/сама строка), а дальше уже дело техники.
Кроме прочего, в процессе копания в данном скрипте я обнаружил еще одно забавное обстоятельство. Некоторым людям катастрофически не хватает возможности создавать комментарии не построчно, а блоками (по аналогии с /*таким комментарием*/). Но любой текст, написанный в области, которая никогда не будет исполняться, обладает всеми необходимыми свойствами. Таким образом комментировать текст можно, например, и так:
goto EndofComment
Comment 1
Comment 2
…
:EndofComment
Или пользоваться естественными областями. А вот с полюбившимися многим комментариями
Итак, окончательную версию скрипта можно найти здесь:text и dict.bat. Не забудьте перед использованием хотя бы один раз выполнить команду dict add, иначе словарю просто нечего будет отображать.
Не уверен, что скрипт пригодится многим, но всё же стоит отметить: его область применения несколько шире заявленной. При желании, он может помочь заучить любые пары термин/объяснение (гипогликемия: снижение концентрации глюкозы в крови) или, скажем, пол правила/вторая половина правила (Жи-Ши: пиши через И). Ну и, в любом случае, главная цель всего этого мероприятия – получение удовольствия – лично для меня была выполнена. Очень надеюсь, что и вы разделили его со мной. На этой замечательной ноте я, пожалуй, завершу статью обещанным дисклеймером.
Дисклеймер
Формат и тема статьи далеко не новы, что позволяет воспользоваться статистически обоснованным опытом предыдущих авторов и сразу ответить на десяток-другой НУ ОЧЕНЬ распространенных вопросов
1. Уважаемый автор, где вы нашли руки достаточной кривизны для написания такой статьи/скрипта? Здесь же <список-непростительных-и-ужасных-ошибок>
Не стреляйте в пианиста, он играет как умеет. За конструктивную критику всегда искренне благодарен, но я вряд ли смогу соответствовать запросам достаточно искушенных людей. Пост является пробой пера, а скрипты – маленьким хобби. Пожалуйста, относитесь к ним соответствующе.
2. Я ничего не понял/я и так всё знаю. Зачем вы всё это понаписали тут?
Как это ни прискорбно, информация не может быть сверхинтересной для всех представителей
3. Ну хорошо, для кого статья мы выяснили. А скрипт то кому нужен? Его практическая польза пренебрежимо мала.
Цель именно данного скрипта – расширение словарного запаса пользователя – является больше поводом покопаться в возможностях старичка-калеки CMD и впихнуть невпихуемое решить кучу возникающих проблем при помощи тех или иных костылей. Приятная и интересная разминка для мозга.
4. А вы вообще в курсе, что при помощи моего любимого <bash/powershell/etc> такие задачи решаются в полстроки?
Судя по распространенности этого вопроса, без такого холивара жизнь теряет всю свою остроту и краски. Но давайте всё же ради разнообразия попробуем его избежать. CMD является отличным местом для концентрированных костылей и хаков, именно их иногда очень не хватает в свободное от работы время. Цель подобных задач получить fun. В некоторых случаях кроме fun’a получается еще и что-то полезное.
5. Мне кажется, эта статья не нова и опирается на кучу других источников.
Безусловно. Она имеет множество важных идейных вдохновителей, привнесших в нее, равно как и в моё мировоззрение, свою частичку, и имя им Легион. Но одного я не могу не выделить среди прочих, это небезызвестная здесь статья уроки batаники.