{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Блоги: заметки с тегом bash",
    "_rss_description": "Автоматически собираемая лента заметок, написанных в блогах на Эгее",
    "_rss_language": "ru",
    "_itunes_email": "",
    "_itunes_categories_xml": "",
    "_itunes_image": false,
    "_itunes_explicit": "no",
    "home_page_url": "https:\/\/blogengine.ru\/blogs\/tags\/bash\/",
    "feed_url": "https:\/\/blogengine.ru\/blogs\/tags\/bash\/json\/",
    "icon": false,
    "authors": [
        {
            "name": "Илья Бирман",
            "url": "https:\/\/blogengine.ru\/blogs\/",
            "avatar": false
        }
    ],
    "items": [
        {
            "id": "137570",
            "url": "https:\/\/bolknote.ru\/all\/oshmyotki-v-konsoli\/",
            "title": "Ошмётки в консоли",
            "content_html": "<p>Как известно, много лет назад «Эпл» перешла с процессоров «Интел» на собственные, основанные на архитектуре «АРМ». Процессоры несовместимы, однако бинарные программы, скомпилированные под «Интел», продолжают работать — в «МакОС» встроен специальный транслятор, который обеспечивает такую возможность.<\/p>\n<p>Много лет я таскаю с собой различные утилиты, которые при переходе с одного «Макбука» на другой автоматически копируются при помощи встроенной в ОС процедуры миграции. Однако некоторое время назад я занялся тем, что с помощью <tt>brew<\/tt> перевёл всё это бинарное хозяйство на «АРМ».<\/p>\n<p>По пути у меня что-то неприятно сломалось — иногда, при редактировании командной строки, всё странно съезжало, части текста наезжали друг на друга и невозможно было понять какая команда получится в итоге.<\/p>\n<p>Я всю голову сломал, пытаясь понять что же произошло, даже переставил себе <i>iTerm2<\/i>, думал дело в нём, но не помогло. Подумал, что может у меня что-то такое погружается при старте терминала, что всё ломает. В итоге стал отключать команды по одной строке в <tt>.bash_profile<\/tt>, пока не отключил строку с переменной <tt>PS1<\/tt>, задающей вид приглашения перед вводом программы, и всё стало нормально работать.<\/p>\n<p>Тут я каким-то образом догадался, что дело в кодах, задающих цвет приглашения. Спросил у ЧатаГПТ и тот подтвердил мою догадку.<\/p>\n<p>Оказывается библиотека <tt>readline<\/tt>, отвечающая за редактирование текста в командной строке, неправильно считает длину строки, если в ней есть управляющие символы, — например, задающие цвет. Чтобы всё работало как надо, их надо обрамлять специальными последовательностями <tt>\\[<\/tt> и <tt>\\]<\/tt>. Если я когда-то это и знал, то успел прочно забыть.<\/p>\n<p>В общем, я заменил приглашение с<\/p>\n<pre class=\"e2-text-code\"><code class=\"bash\">PS1=&#039;\\e[33;1m\\u: \\e[31m\\W$(__git_ps1)\\e[0m \\$ &#039;<\/code><\/pre><p>на<\/p>\n<pre class=\"e2-text-code\"><code class=\"bash\">PS1=&#039;\\[\\e[33;1m\\]\\u:\\[\\e[0m\\] \\[\\e[31m\\]\\W$(__git_ps1)\\[\\e[0m\\] \\$ &#039;<\/code><\/pre><p>и всё заработало как надо.<\/p>\n",
            "date_published": "2025-09-26T00:30:42+05:00",
            "date_modified": "2025-09-26T00:30:29+05:00",
            "tags": [
                "bash",
                "macos",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Fri, 26 Sep 2025 00:30:42 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "137570",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "133093",
            "url": "https:\/\/bolknote.ru\/all\/bash-httpd\/",
            "title": "Bash HTTPd",
            "content_html": "<p>У писателя Леонида Каганова, который в последние годы ушёл в айти, началась какая-то полоса невезения. Много чего случилось, пересказывать долго, а сослаться пока некуда — ко всем неприятностям у него ещё и сайт перестал работать.<\/p>\n<p>Я ему сегодня утром пытался хоть чем-то помочь — посоветовал какие команды писать, чтобы вывести из состава рейда отказавший диск и переписать данные. Другой его знакомый смог загрузиться с внешнего загрузочного диска, увидеть системный раздел и они вместе сейчас скачивают всё что нужно.<\/p>\n<p>В процессе там понадобился какой-нибудь простой веб-сервер, чтобы выдернуть что-то наживую. Я, конечно, вспомнил про Пайтон, где это делается одной строкой, но оказалось, что операционка, с которой удалось загрузиться, его не содержит, поэтому я нашёл <a href=\"https:\/\/gist.github.com\/alexey-sveshnikov\/69d502aefd05a539c165\">другую реализацию<\/a> — на «баше».<\/p>\n<p>Обошлись без веб-сервера, но пока суд да дело, выяснилось, что у меня на ноутбуке этот башевский сервер не работает — у меня «Макось», а у местной утилиты <tt>nc<\/tt> нет ключа <tt>-c<\/tt> при помощи которой можно указать команду для обработки данных из сокета.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2024.12.04@2x.webp\" width=\"1000\" height=\"502\" alt=\"\" \/>\n<\/div>\n<p>В общем, мне стало как-то обидно, что автор оригинального кода обошёл вниманием «Макось» и я написал <a href=\"https:\/\/github.com\/bolknote\/BashHTTPd\/blob\/main\/http-formatted.sh\">свою реализацию<\/a> через команду <tt>coproc<\/tt>, которую до этого использовать не умел. Вот и появился повод изучить.<\/p>\n<p>В процессе код стал занимать меньше места (моя <a href=\"https:\/\/github.com\/bolknote\/BashHTTPd\/blob\/main\/http.sh\">минифицированная версия<\/a> на 25 байт короче), научился обрабатывать имена, содержащие пробелы и национальные символы и заработал не только под «Линуксом», но и под «Макосью».<\/p>\n",
            "date_published": "2024-12-04T22:18:04+05:00",
            "date_modified": "2024-12-05T15:32:50+05:00",
            "tags": [
                "bash",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Wed, 04 Dec 2024 22:18:04 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "133093",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "133015",
            "url": "https:\/\/bolknote.ru\/all\/bash-the-wumpus\/",
            "title": "Bash The Wumpus",
            "content_html": "<p>Образовалась на днях у меня в голове доброкачественная идея — сделать какую-нибудь несложную игру в командной строке и чтобы непременно игровым полем была файловая система.<\/p>\n<p>Директории будут комнатами, ходить туда-сюда можно будет стандартной командой смены директория — <tt>cd<\/tt>, игровые предметы или монстры должны быть файлами, ну и так далее.<\/p>\n<p>Для реализации выбрал тот же классический квест 1970-х, который я переписывал для <a href=\"https:\/\/bolknote.ru\/tags\/sensor-watch\/\"><i>The Sensor Watch<\/i><\/a> — «<i>Hunt The Wumpus<\/i>». Вампус там живёт в пещере, который представляет с собой граф из двадцати помещений, соединённых в додекаэдр.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2024.11.30@2x.webp\" width=\"500\" height=\"250\" alt=\"\" \/>\n<div class=\"e2-text-caption\">Самая быстрая моя победа, я даже не задумался, что если бы стрела не убила Вампуса сразу, то следующим ходом убила бы меня<\/div>\n<\/div>\n<p>В соответствии с идеей, помещения у меня представлены директориями, а переходы между ними — символическими ссылками. Соответственно, Вампус и прочие опасности, — ямы и летучие мыши, стали файлами.<\/p>\n<p>В первой версии у меня всё было организовано обычными командами. Кроме упомянутой <tt>cd<\/tt>, вполне естественным способом заработали <tt>ls<\/tt> и <tt>pwd<\/tt>, а так же команда <tt>rm<\/tt>, которая уничтожала файлы-монстры.<\/p>\n<p>К сожалению, это было слишком похоже на «молдавский вирус» («ввиду общей отсталости развития высоких технологий нашей страны, пожалуйста, сотрите сами несколько самых нужных вам файлов, а затем разошлите меня по почте своим друзьям»), пришлось добавить командам кое-какие проверки и интерактив.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2024.11.30.1@2x.webp\" width=\"500\" height=\"450\" alt=\"\" \/>\n<div class=\"e2-text-caption\">Тут мне повезло меньше<\/div>\n<\/div>\n<p>Сначала я сделал проверки через <tt>trap<\/tt> сигнала <tt>DEBUG<\/tt> и обработку произошедшего через скрипт, который запускается из переменной подсказки <tt>PS1<\/tt>, но в итоге пришлось подменить ряд команд алиасами и вызовами функций.<\/p>\n<p>Чтобы сохранить вайб консоли семидесятых, сообщения в игровом процессе и инструкцию я взял из <a href=\"https:\/\/www.atariarchives.org\/bcc1\/showpage.php?page=250\">оригинальной игры<\/a> и оставил всё в верхнем регистре, как и в оригинале.<\/p>\n<p>Поскольку команды подаются в консоли, можно выиграть почти сразу, если знать парочку фокусов. Я постарался осложнить их использование, но все возможности не закрыл, это противоречит изначальной идее.<\/p>\n<p>Игра, как обычно, <a href=\"https:\/\/github.com\/bolknote\/Bash-The-Wumpus\">выложена<\/a> на «Гитхабе».<\/p>\n",
            "date_published": "2024-11-30T16:04:48+05:00",
            "date_modified": "2024-11-30T15:58:44+05:00",
            "tags": [
                "bash",
                "Игра",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Sat, 30 Nov 2024 16:04:48 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "133015",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "127159",
            "url": "https:\/\/bolknote.ru\/all\/cmd-sh\/",
            "title": "cmd.sh",
            "content_html": "<p>Я тут случайно в спор ввязался — можно ли переписать бат-файл так, чтобы он запускался и выводил примерно одинаковый результат на трёх основных операционных системах — Виндоузе, Линуксе и МакОСи.<\/p>\n<p>Речь шла о вполне определённом файле, там запрограммировано небольшое меню и в зависимости от выбранного пункта запускается та или иная, одинаковая для всех ОС, последовательность команд.<\/p>\n<p>Мой собеседник мне не верил, когда я утверждал, что это вполне возможно, и требовал доказательств.<\/p>\n<p>Что ж. Основная моя идея была в том, чтобы заменить команды батника на вызовы баш-функций, которые я спрячу в специальных конструкциях. В Виндоузе файл обработает обычный <tt>cmd.exe<\/tt>, на остальных операционках — <tt>bash<\/tt>.<\/p>\n<p>То, что мне предстояло адаптировать начиналось вполне стандартно:<\/p>\n<pre class=\"e2-text-code\"><code class=\"php\">@ECHO off\nCHCP 1251\nCLS<\/code><\/pre><p>Что тут происходит? Выключается вывод команд на экран (при адаптации это можно игнорировать), ставится однобайтовая кодировка <i>CP1251<\/i> (это хорошо бы учесть) и очищается экран.<\/p>\n<p>Поскольку «баш» этих команд не знает, надо определить три функции, спрятав их от <tt>cmd.exe<\/tt>. Сделать это несложно. Команду «двоеточие» <tt>cmd.exe<\/tt> трактует как начало метки и на дальнейшее не реагирует, а «баш» считает её пустой командой, которую можно точкой с запятой отделить от строки, которую мы хотим спрятать:<\/p>\n<pre class=\"e2-text-code\"><code class=\"bash\">:; @ECHO() { :;}; CLS() { clear; }; CHCP() { ENC=&quot;$1&quot;; }<\/code><\/pre><p>Следующее, чему надо научиться — выводить текст в указанной в батнике кодировке. Это просто:<\/p>\n<pre class=\"e2-text-code\"><code class=\"bash\">:; ECHO.() { echo $@ | iconv -f &quot;CP$ENC&quot;; }<\/code><\/pre><p>Если теперь сделать файл запускаемым и добавить впереди <tt>#!\/bin\/bash<\/tt> (и пренебречь тем, что <tt>cmd.exe<\/tt> успевает ругнуться на эту строку до очистки экрана), у нас получится следующий файл, работающий во всех трёх операционках (кодировка должна быть <i>Windows-1251<\/i>):<\/p>\n<pre class=\"e2-text-code\"><code class=\"bash\">#!\/bin\/bash\n:; @ECHO() { :;}; CLS() { clear; }; CHCP() { ENC=&quot;$1&quot;; }\n@ECHO off\nCHCP 1251\nCLS\n:; ECHO.() { echo $@ | iconv -f &quot;CP$ENC&quot;; }\nECHO. Всем привет<\/code><\/pre><p>А вот дальше сложнее. Само меню организовано в оригинале так:<\/p>\n<pre class=\"e2-text-code\"><code class=\"php\">SET \/p opt=Введите цифру:\n\nIF %opt%==1 GOTO dns_auto\nIF %opt%==2 GOTO dnschange\nIF %opt%==3 GOTO exit<\/code><\/pre><p>В «баше» <tt>goto<\/tt> (переход к метке) отсутствует и это проблема. Аналогов тоже нет. Единственное, что тут можно сделать — использовать вызов функций, но синтаксис в «бате» и «баше» сильно различается.<\/p>\n<p>Как быть? Во-первых, сэмулировать функцией команду <tt>SET<\/tt>, во-вторвых, упростить это место, чтобы меньше было писать кода на «баше»:<\/p>\n<pre class=\"e2-text-code\"><code class=\"bash\">:; SET() { shift; ECHO. -n &quot;${@#*=}&quot;; read -n1 &quot;${1%%=*}&quot;; echo; }\n:; CALL() { eval &quot;$(sed &#039;s\/%\\(.*\\)%\/$\\1\/g&#039; &lt;&lt;&lt; &quot;$1&quot;)&quot; 2&gt;&amp;-; }\n\nSET \/p opt=Введите цифру:\nCALL :menu_%opt%<\/code><\/pre><p>Первая функция парсит команду <tt>SET<\/tt> выводит строку после равно, ждёт ввода и записывает значение в имя переменной, указанной слева от равно.<\/p>\n<p>Вторая — заменяет <tt>CALL<\/tt>. В ней <tt>%variable%<\/tt> заменяется на <tt>$variable<\/tt>, выполняется подстановка переменной и получившееся имя выполняется как команда или функция «баша». Конструкция <tt>2&gt;&amp;-<\/tt> нужна, чтобы избежать вывода ошибки в ситуации, если пользователь введёт что-нибудь не то.<\/p>\n<p>Теперь надо как-то научиться определять функции так, чтобы их нормально «видел» и <tt>cmd.exe<\/tt>, и «баш». В батнике функции — просто любое место программы, начинающееся с метки и заканчивающееся вызовом <tt>GOTO :EOF<\/tt>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"php\">:function_1\nECHO это якобы функция\nGOTO :EOF<\/code><\/pre><p>В «баше» то же самое могло бы выглядеть, например, так:<\/p>\n<pre class=\"e2-text-code\"><code class=\"bash\">function_1() {\n    echo это функция\n}<\/code><\/pre><p>Как это объединить? Я придумал следующий подход:<\/p>\n<pre class=\"e2-text-code\"><code class=\"bash\">:; GOTO() { :; };\n\nGOTO ;#start\n:function_1 (){\nECHO. это [якобы] функция\nGOTO :EOF\n:; }\n\n:;#start<\/code><\/pre><p>В первой строке определяется пустая функция для «баша», потому что эта часть синтаксиса бат-файла нам не нужна.<\/p>\n<p>Ниже идёт строка <tt>GOTO ;#start<\/tt>. С точки зрения «баша» тут две конструкции — <tt>GOTO<\/tt>, которая вызывает определённую выше пустую функцию и <tt>#start<\/tt> — строка комментария, так как в«баше» с «решётки» начинаются комментарии.<\/p>\n<p>В «батнике» же эта же строка будет означать переход к метке с именем <tt>;#start<\/tt>. Этот переход нужен нам, чтобы «обогнуть» строки, которые определены ниже, иначе <tt>cmd.exe<\/tt> начнёт сразу их выполнять, а нам этого не нужно. Их нельзя «спрятать» ниже основной программы, так как в «баше» функции должны определены раньше их вызова.<\/p>\n<p>Что происходит дальше? С точки зрения <tt>cmd.exe<\/tt> ниже расположена метка <tt>:function_1<\/tt> (как показывают мои эксперименты, часть после пробела просто отбрасывается), потом тело функции, команда её завершения <tt>GOTO :EOF<\/tt> и метка с именем <tt>:;}<\/tt>.<\/p>\n<p>С точки зрения «баша» там определяется функция с именем <tt>:function_1<\/tt>, ниже идут вызовы уже определённых мною функций <tt>ECHO.<\/tt> и <tt>GOTO<\/tt>, а ещё ниже — уже знакомая нам пустая команда <tt>:<\/tt> и фигурная скобка, завершающая тело функции.<\/p>\n<p>Соединяем всё вместе и получается следующая программа:<\/p>\n<pre class=\"e2-text-code\"><code class=\"bash\">#!\/bin\/bash\n:; @ECHO() { :;}; CLS() { clear; }; CHCP() { ENC=&quot;$1&quot;; }\n@ECHO off\nCHCP 1251\nCLS\n\n:; GOTO() { :; };\n:; ECHO.() { echo $@ | iconv -f &quot;CP$ENC&quot;; }; PAUSE() { read; }; \n:; SET() { shift; ECHO. -n &quot;${@#*=}&quot;; read &quot;${1%%=*}&quot;; }\n:; CALL() { eval &quot;$(sed &#039;s\/%\\(.*\\)%\/$\\1\/g&#039; &lt;&lt;&lt; &quot;$1&quot;)&quot; 2&gt;&amp;-; }\n\nGOTO ;#start\n\n:menu_1 (){\nECHO. Пункт первый\nGOTO :EOF\n:; }\n\n:menu_2 (){\nECHO. Пункт второй\nGOTO :EOF\n:; }\n\n:;#start\n\nSET \/p opt=Введите цифру:\nCALL :menu_%opt%<\/code><\/pre><p>Мой оппонент признал, что в споре я победил.<\/p>\n",
            "date_published": "2024-04-06T00:26:05+05:00",
            "date_modified": "2024-04-06T15:19:40+05:00",
            "tags": [
                "bash",
                "cmd",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Sat, 06 Apr 2024 00:26:05 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "127159",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "118754",
            "url": "https:\/\/bolknote.ru\/all\/nenormalny-cikl-na-bashe\/",
            "title": "Ненормальный цикл на «баше»",
            "content_html": "<p>Сегодня в чате бывших коллег на фоне вопросов по одной из вакансий случилось обсуждение на тему что делать, если на собеседовании спросили как написать на «баше» цикл от одного до десяти, а ты не помнишь синтаксис и команду <tt>seq<\/tt> тоже не знаешь.<\/p>\n<p>Предположим ты честно говоришь, что не помнишь, а тебя просят как-то выкрутиться теми знаниями, которые есть.<\/p>\n<p>Мой вариант:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2023.04.24.1@2x.jpg\" width=\"1000\" height=\"281\" alt=\"\" \/>\n<\/div>\n",
            "date_published": "2023-04-24T20:25:17+05:00",
            "date_modified": "2023-04-24T20:25:12+05:00",
            "tags": [
                "bash",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Mon, 24 Apr 2023 20:25:17 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "118754",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "118789",
            "url": "https:\/\/bolknote.ru\/all\/4432\/",
            "title": "👁 Глаз следящий",
            "content_html": "<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2016.03.05@2x.jpg\" width=\"374\" height=\"266\" alt=\"\" \/>\n<div class=\"e2-text-caption\">Глаз, следящий за мышью в консоли<\/div>\n<\/div>\n<p>Обновилась до версии 2.9 моя любимая программа-терминал <i>iTerm2<\/i>. Изучая новые возможности, обнаружил нечто неожиданное — теперь в консоль <a href=\"https:\/\/www.iterm2.com\/images.html\">можно выводить<\/a> обычные графические изображения.<\/p>\n<p>Протокол довольно простой:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">ESC ] 1337 ; File = [необязательные параметры] : изображение в формате base64 ^G<\/code><\/pre><\/pre><p>Решил немного с ним побаловаться, результат на скриншоте — небольшая программа на «баше» — <a href=\"https:\/\/github.com\/bolknote\/shellgames\/blob\/master\/eye.bash\">глаз, который следит за указателем мыши<\/a>.<\/p>\n<p>Пришлось разобраться с тем как вообще получают координаты мыши в консоли, плюс вспомнить школьную геометрию. Синусы, косинусы, вот это всё, неявно вычисляются через <i>awk<\/i> и используются для определения где нужно рисовать зрачок.<\/p>\n<p>Чем дальше курсор находится от глаза, тем больше событий мыши получает консоль во время перемещений по окружности вокруг него. Из-за этого образуется некая инерционность слежения, которую я стал было корректировать, но потом убрал этот код — инерция придаёт какое-то интересное подобие жизни.<\/p>\n<p>Для запуска требуется <i>iTerm2<\/i> 2.9 и выше и <i>Imagemagick<\/i>.<\/p>\n",
            "date_published": "2016-03-05T22:13:00+05:00",
            "date_modified": "2023-04-26T23:11:56+05:00",
            "tags": [
                "bash",
                "macos",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Sat, 05 Mar 2016 22:13:00 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "118789",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "133178",
            "url": "https:\/\/bolknote.ru\/all\/4251\/",
            "title": "Как работает Bashfuck",
            "content_html": "<p>Думаю, по горячим следам надо описать как работают мои <a href=\"\/2014\/12\/09\/~4248\"><i>Bashfuck<\/i><\/a> и <a href=\"\/2014\/12\/10\/~4250\"><i>Bashfuck-2<\/i><\/a>. Пока ещё сам детально помню.<\/p>\n<p>Поскольку буквы и цифры использовать запрещено, все имена переменных состоят исключительно из подчёркиваний — это единственный вариант в «Баше» в таком случае. Чтобы что-то напечатать, сначала надо получить какие-то буквы.<\/p>\n<p>К счастью, переменная с именем, состоящим из одного подчёркивания содержит полный путь к интерпретатору, которым был запущен наш скрипт. Поскольку путь может отличаться, а название интерпретатора — нет, путь надо удалить, оставив только слово «<i>bash<\/i>». Это делается в обоих случая в первой строке:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\"># Удаляем из переменной $_ всё до последнего слеша\n__=${_##*\/}<\/code><\/pre><\/pre><p>Теперь у нас есть четыре буквы «<i>b<\/i>», «<i>a<\/i>», «<i>s<\/i>» и «<i>h<\/i>». Из имеющегося надо как-то получить недостающее. Тут нам помогает следующий факт: можно запускать что угодно, по имени, которое содержится в переменной.<\/p>\n<p>Далее оба скрипта пытаются составить в одной из переменных команду «<i>base64<\/i>», чтобы передав ей на вход строку, получить недостающие буквы. В самом деле, передавая на вход разные строки и пропуская их по нескольку раз через «<i>base64<\/i>» команду, можно получить весь английский алфавит:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\"># bash тут — строка, которую мы уже получили\n$ base64&lt;&lt;&lt;bash\nYmFzaAo=\n$ base64&lt;&lt;&lt;bash | base64\nWW1GemFBbz0K<\/code><\/pre><\/pre><p>Например, в полученных строках некоторые буквы нам вполне интересны: «<i>Hell<b>o<\/b> <b>wo<\/b>rld<\/i>». Но как получить слово <i>base64<\/i>? С цифрами проще: имея строки разной длины и арифметические операции можно получить нужное:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\"># Переменная __ содержит слово bash\n__=bash\n# Очень просто получить цифру четыре: надо измерить длину строки:\n$ echo ${#__}\n4\n# Любым похожим путём получаем двойку, прибавляем к четвёртке и у нас есть 6\n$ echo $((${#__} + 2))\n6<\/code><\/pre><\/pre><p>Поскольку типы переменных «Баш» не особо-то различает, склеить всё остальное труда не представляет. Но нужно ещё откуда-то получить букву «<i>e<\/i>». Тут дорожки этих двух скриптов расходятся. Первый работает так: составляя из имеющихся букв команду «<i>hash<\/i>», запускает её и получает следующую строку:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">$ hash\nhash: hash table empty<\/code><\/pre><\/pre><p>Второй действует интереснее. Есть такой синтаксис для команд, которые на вход принимают только файл: можно передать вывод другой команды особым образом и интерпретатор подставит в параметр специальное имя псевдофайла из которого можно прочитать упомянутый вывод.<\/p>\n<p>Если использовать такой синтаксис с любой командой, которая принимает не файл, а строку, то строку и получим (цифры будут меняться от запуска к запуску, остальная строка останется неизменной):<\/p>\n<pre class=\"e2-text-code\"><code class=\"\"># пробуем вывести на печать\n$ echo &lt;(:)\n\/dev\/fd\/63<\/code><\/pre><\/pre><p>Нам это значение нужно в переменной и с присвоением этот трюк тоже сработет.<\/p>\n<p>В том и другом скрипте нужную букву мы получили и можем собрать нужное имя без проблем. Для этого воспользуемся следующей конструкцией, которая позволяет выбирать подстроки из переменных:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\"># переменная теперь содержит что-то вроде \/dev\/fd\/xx\n___=&lt;(:)\n# выбираем третий символ (отсчёт с нуля):\necho ${___:2:1}<\/code><\/pre><\/pre><p>Вместо двойки и единицы можно подставить переменные, которые эти числа содержат, либо вычислить их по ходу дела. Во втором примере применяется ещё и другая техника —  поскольку некоторые числа из подручных переменных вычислять сложно, я срезаю некоторое количество букв слева и справа, чтобы добраться до нужной буквы:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\"># переменная, где нужная мне буква в середине слова\nv=sed\n# так можно срезать последнюю букву\necho ${v%?}\n# а так —  первую\necho ${v#?}<\/code><\/pre><\/pre><p>По большому счёту, это всё. Используется ещё несколько приёмов, но для понимания происходящего осталось пояснить только ещё одну вещь. В четвёртом «Баше», который требуется для работы обоих скриптов, есть ещё такой специальный синтаксис, который позволяет менять регистр букв. Это позвояет не заморачиваться с тем, в каком регистре получаются отдельные буквы и првести всё к нужному ближе к концу:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">v=&#039;heLLo WORld&#039;\n# всё к нижнему (будет hello world)\necho ${v,,}\n# только первую —  к верхнему (будет HeLLo WORld)\necho ${v^}<\/code><\/pre><\/pre><p>Собранную строку осталось вывести на экран. Для этого в том же коде я попутно собираю из получающихся букв ещё и строку «<i>cat<\/i>» (что на одну букву меньше «<i>echo<\/i>», кода получается меньше) и с помощью этой команды получаю нужный результат:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">c=cat\nv=&#039;Hello world&#039;\n# Выведет Hello world\n$c&lt;&lt;&lt;$v<\/code><\/pre><\/pre><p>Можно, кстати, попробовать ещё задействовать функции, благо их объявление алфавитных символов не требует, а их имена могут подержать не только подчёркивания (но и, например, «собаку», что даёт бо́льшую свободу), но третий вариант я уже делать не буду, надоело.<\/p>\n",
            "date_published": "2014-12-10T21:44:00+05:00",
            "date_modified": "2024-12-09T15:25:33+05:00",
            "tags": [
                "*fuck",
                "bash",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Wed, 10 Dec 2014 21:44:00 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "133178",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "133884",
            "url": "https:\/\/bolknote.ru\/all\/3724\/",
            "title": "Удаляем расладку «U.S. English» из «Мака»",
            "content_html": "<p>Артём Поликарпов <a href=\"https:\/\/web.archive.org\/web\/20120827053608\/http:\/\/artpolikarpov.ru\/2012\/08\/24\/1\/\">написал<\/a> рецепт как можно удалить из «Мака» раскладку «U.S. English». Она очень мешается и совершенно не нужна, если поставить великолепную <a href=\"http:\/\/ilyabirman.ru\/projects\/typography-layout\/\">раскладку Ильи Бирмана<\/a> (кстати, если вы почему-то ей не пользуетесь, то вы делаете большую ошибку).<\/p>\n<p>Но рецепт Артёма мне не нравится тем, что для его выполнения приходится иметь у себя редактор <i>Xcode<\/i>, который ещё и несколько гигабайт весит. Поэтому я, как водится, <a href=\"https:\/\/github.com\/bolknote\/shellgames\/blob\/master\/us_layout_remover.sh\">написал скрипт<\/a>, который нужно выполнить из «Терминала» (после его выполнения придётся опять залогиниться в систему) и ненужной раскладки уже не будет.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/bolknote.ru\/pictures\/2012.08.24.png\" width=\"297\" height=\"112\" alt=\"\" \/>\n<div class=\"e2-text-caption\">Ничего ненужного<\/div>\n<\/div>\n<p>Какое счастье!<\/p>\n<p>Проще всего скрипт запускать из «Терминала» вот так:<\/p>\n<pre class=\"e2-text-code\"><code class=\"bash\">bash  &lt;(curl -fsSkL raw.github.com\/bolknote\/shellgames\/master\/us_layout_remover.sh)<\/code><\/pre><p>Чтобы вернуть всё обратно достаточно запустить программу ещё раз.<\/p>\n<p><i>Добавлено позднее<\/i>: удалению раскладки <a href=\"https:\/\/bolknote.ru\/all\/3724\/\">может мешать<\/a> <i>Punto Switcher<\/i>.<\/p>\n",
            "date_published": "2012-08-25T00:48:00+05:00",
            "date_modified": "2025-02-01T13:28:43+05:00",
            "tags": [
                "bash",
                "macos",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Sat, 25 Aug 2012 00:48:00 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "133884",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        }
    ],
    "_e2_version": 4079,
    "_e2_ua_string": "Aegea 11.0 (v4079e)"
}