<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:atom="http://www.w3.org/2005/Atom">

<channel>

<title>Блоги: заметки с тегом bash</title>
<link>https://blogengine.ru/blogs/tags/bash/</link>
<description>Автоматически собираемая лента заметок, написанных в блогах на Эгее</description>
<author></author>
<language>ru</language>
<generator>Aegea 11.0 (v4079e)</generator>

<itunes:subtitle>Автоматически собираемая лента заметок, написанных в блогах на Эгее</itunes:subtitle>
<itunes:image href="" />
<itunes:explicit>no</itunes:explicit>

<item>
<title>Ошмётки в консоли</title>
<guid isPermaLink="false">137570</guid>
<link>https://bolknote.ru/all/oshmyotki-v-konsoli/</link>
<pubDate>Fri, 26 Sep 2025 00:30:42 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/oshmyotki-v-konsoli/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Как известно, много лет назад «Эпл» перешла с процессоров «Интел» на собственные, основанные на архитектуре «АРМ». Процессоры несовместимы, однако бинарные программы, скомпилированные под «Интел», продолжают работать — в «МакОС» встроен специальный транслятор, который обеспечивает такую возможность.&lt;/p&gt;
&lt;p&gt;Много лет я таскаю с собой различные утилиты, которые при переходе с одного «Макбука» на другой автоматически копируются при помощи встроенной в ОС процедуры миграции. Однако некоторое время назад я занялся тем, что с помощью &lt;tt&gt;brew&lt;/tt&gt; перевёл всё это бинарное хозяйство на «АРМ».&lt;/p&gt;
&lt;p&gt;По пути у меня что-то неприятно сломалось — иногда, при редактировании командной строки, всё странно съезжало, части текста наезжали друг на друга и невозможно было понять какая команда получится в итоге.&lt;/p&gt;
&lt;p&gt;Я всю голову сломал, пытаясь понять что же произошло, даже переставил себе &lt;i&gt;iTerm2&lt;/i&gt;, думал дело в нём, но не помогло. Подумал, что может у меня что-то такое погружается при старте терминала, что всё ломает. В итоге стал отключать команды по одной строке в &lt;tt&gt;.bash_profile&lt;/tt&gt;, пока не отключил строку с переменной &lt;tt&gt;PS1&lt;/tt&gt;, задающей вид приглашения перед вводом программы, и всё стало нормально работать.&lt;/p&gt;
&lt;p&gt;Тут я каким-то образом догадался, что дело в кодах, задающих цвет приглашения. Спросил у ЧатаГПТ и тот подтвердил мою догадку.&lt;/p&gt;
&lt;p&gt;Оказывается библиотека &lt;tt&gt;readline&lt;/tt&gt;, отвечающая за редактирование текста в командной строке, неправильно считает длину строки, если в ней есть управляющие символы, — например, задающие цвет. Чтобы всё работало как надо, их надо обрамлять специальными последовательностями &lt;tt&gt;\[&lt;/tt&gt; и &lt;tt&gt;\]&lt;/tt&gt;. Если я когда-то это и знал, то успел прочно забыть.&lt;/p&gt;
&lt;p&gt;В общем, я заменил приглашение с&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="bash"&gt;PS1=&amp;#039;\e[33;1m\u: \e[31m\W$(__git_ps1)\e[0m \$ &amp;#039;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;на&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="bash"&gt;PS1=&amp;#039;\[\e[33;1m\]\u:\[\e[0m\] \[\e[31m\]\W$(__git_ps1)\[\e[0m\] \$ &amp;#039;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;и всё заработало как надо.&lt;/p&gt;
</description>
</item>

<item>
<title>Bash HTTPd</title>
<guid isPermaLink="false">133093</guid>
<link>https://bolknote.ru/all/bash-httpd/</link>
<pubDate>Wed, 04 Dec 2024 22:18:04 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/bash-httpd/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;У писателя Леонида Каганова, который в последние годы ушёл в айти, началась какая-то полоса невезения. Много чего случилось, пересказывать долго, а сослаться пока некуда — ко всем неприятностям у него ещё и сайт перестал работать.&lt;/p&gt;
&lt;p&gt;Я ему сегодня утром пытался хоть чем-то помочь — посоветовал какие команды писать, чтобы вывести из состава рейда отказавший диск и переписать данные. Другой его знакомый смог загрузиться с внешнего загрузочного диска, увидеть системный раздел и они вместе сейчас скачивают всё что нужно.&lt;/p&gt;
&lt;p&gt;В процессе там понадобился какой-нибудь простой веб-сервер, чтобы выдернуть что-то наживую. Я, конечно, вспомнил про Пайтон, где это делается одной строкой, но оказалось, что операционка, с которой удалось загрузиться, его не содержит, поэтому я нашёл &lt;a href="https://gist.github.com/alexey-sveshnikov/69d502aefd05a539c165"&gt;другую реализацию&lt;/a&gt; — на «баше».&lt;/p&gt;
&lt;p&gt;Обошлись без веб-сервера, но пока суд да дело, выяснилось, что у меня на ноутбуке этот башевский сервер не работает — у меня «Макось», а у местной утилиты &lt;tt&gt;nc&lt;/tt&gt; нет ключа &lt;tt&gt;-c&lt;/tt&gt; при помощи которой можно указать команду для обработки данных из сокета.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2024.12.04@2x.webp" width="1000" height="502" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;В общем, мне стало как-то обидно, что автор оригинального кода обошёл вниманием «Макось» и я написал &lt;a href="https://github.com/bolknote/BashHTTPd/blob/main/http-formatted.sh"&gt;свою реализацию&lt;/a&gt; через команду &lt;tt&gt;coproc&lt;/tt&gt;, которую до этого использовать не умел. Вот и появился повод изучить.&lt;/p&gt;
&lt;p&gt;В процессе код стал занимать меньше места (моя &lt;a href="https://github.com/bolknote/BashHTTPd/blob/main/http.sh"&gt;минифицированная версия&lt;/a&gt; на 25 байт короче), научился обрабатывать имена, содержащие пробелы и национальные символы и заработал не только под «Линуксом», но и под «Макосью».&lt;/p&gt;
</description>
</item>

<item>
<title>Bash The Wumpus</title>
<guid isPermaLink="false">133015</guid>
<link>https://bolknote.ru/all/bash-the-wumpus/</link>
<pubDate>Sat, 30 Nov 2024 16:04:48 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/bash-the-wumpus/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Образовалась на днях у меня в голове доброкачественная идея — сделать какую-нибудь несложную игру в командной строке и чтобы непременно игровым полем была файловая система.&lt;/p&gt;
&lt;p&gt;Директории будут комнатами, ходить туда-сюда можно будет стандартной командой смены директория — &lt;tt&gt;cd&lt;/tt&gt;, игровые предметы или монстры должны быть файлами, ну и так далее.&lt;/p&gt;
&lt;p&gt;Для реализации выбрал тот же классический квест 1970-х, который я переписывал для &lt;a href="https://bolknote.ru/tags/sensor-watch/"&gt;&lt;i&gt;The Sensor Watch&lt;/i&gt;&lt;/a&gt; — «&lt;i&gt;Hunt The Wumpus&lt;/i&gt;». Вампус там живёт в пещере, который представляет с собой граф из двадцати помещений, соединённых в додекаэдр.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2024.11.30@2x.webp" width="500" height="250" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Самая быстрая моя победа, я даже не задумался, что если бы стрела не убила Вампуса сразу, то следующим ходом убила бы меня&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;В соответствии с идеей, помещения у меня представлены директориями, а переходы между ними — символическими ссылками. Соответственно, Вампус и прочие опасности, — ямы и летучие мыши, стали файлами.&lt;/p&gt;
&lt;p&gt;В первой версии у меня всё было организовано обычными командами. Кроме упомянутой &lt;tt&gt;cd&lt;/tt&gt;, вполне естественным способом заработали &lt;tt&gt;ls&lt;/tt&gt; и &lt;tt&gt;pwd&lt;/tt&gt;, а так же команда &lt;tt&gt;rm&lt;/tt&gt;, которая уничтожала файлы-монстры.&lt;/p&gt;
&lt;p&gt;К сожалению, это было слишком похоже на «молдавский вирус» («ввиду общей отсталости развития высоких технологий нашей страны, пожалуйста, сотрите сами несколько самых нужных вам файлов, а затем разошлите меня по почте своим друзьям»), пришлось добавить командам кое-какие проверки и интерактив.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2024.11.30.1@2x.webp" width="500" height="450" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Тут мне повезло меньше&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Сначала я сделал проверки через &lt;tt&gt;trap&lt;/tt&gt; сигнала &lt;tt&gt;DEBUG&lt;/tt&gt; и обработку произошедшего через скрипт, который запускается из переменной подсказки &lt;tt&gt;PS1&lt;/tt&gt;, но в итоге пришлось подменить ряд команд алиасами и вызовами функций.&lt;/p&gt;
&lt;p&gt;Чтобы сохранить вайб консоли семидесятых, сообщения в игровом процессе и инструкцию я взял из &lt;a href="https://www.atariarchives.org/bcc1/showpage.php?page=250"&gt;оригинальной игры&lt;/a&gt; и оставил всё в верхнем регистре, как и в оригинале.&lt;/p&gt;
&lt;p&gt;Поскольку команды подаются в консоли, можно выиграть почти сразу, если знать парочку фокусов. Я постарался осложнить их использование, но все возможности не закрыл, это противоречит изначальной идее.&lt;/p&gt;
&lt;p&gt;Игра, как обычно, &lt;a href="https://github.com/bolknote/Bash-The-Wumpus"&gt;выложена&lt;/a&gt; на «Гитхабе».&lt;/p&gt;
</description>
</item>

<item>
<title>cmd.sh</title>
<guid isPermaLink="false">127159</guid>
<link>https://bolknote.ru/all/cmd-sh/</link>
<pubDate>Sat, 06 Apr 2024 00:26:05 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/cmd-sh/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Я тут случайно в спор ввязался — можно ли переписать бат-файл так, чтобы он запускался и выводил примерно одинаковый результат на трёх основных операционных системах — Виндоузе, Линуксе и МакОСи.&lt;/p&gt;
&lt;p&gt;Речь шла о вполне определённом файле, там запрограммировано небольшое меню и в зависимости от выбранного пункта запускается та или иная, одинаковая для всех ОС, последовательность команд.&lt;/p&gt;
&lt;p&gt;Мой собеседник мне не верил, когда я утверждал, что это вполне возможно, и требовал доказательств.&lt;/p&gt;
&lt;p&gt;Что ж. Основная моя идея была в том, чтобы заменить команды батника на вызовы баш-функций, которые я спрячу в специальных конструкциях. В Виндоузе файл обработает обычный &lt;tt&gt;cmd.exe&lt;/tt&gt;, на остальных операционках — &lt;tt&gt;bash&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;То, что мне предстояло адаптировать начиналось вполне стандартно:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="php"&gt;@ECHO off
CHCP 1251
CLS&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Что тут происходит? Выключается вывод команд на экран (при адаптации это можно игнорировать), ставится однобайтовая кодировка &lt;i&gt;CP1251&lt;/i&gt; (это хорошо бы учесть) и очищается экран.&lt;/p&gt;
&lt;p&gt;Поскольку «баш» этих команд не знает, надо определить три функции, спрятав их от &lt;tt&gt;cmd.exe&lt;/tt&gt;. Сделать это несложно. Команду «двоеточие» &lt;tt&gt;cmd.exe&lt;/tt&gt; трактует как начало метки и на дальнейшее не реагирует, а «баш» считает её пустой командой, которую можно точкой с запятой отделить от строки, которую мы хотим спрятать:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="bash"&gt;:; @ECHO() { :;}; CLS() { clear; }; CHCP() { ENC=&amp;quot;$1&amp;quot;; }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Следующее, чему надо научиться — выводить текст в указанной в батнике кодировке. Это просто:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="bash"&gt;:; ECHO.() { echo $@ | iconv -f &amp;quot;CP$ENC&amp;quot;; }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Если теперь сделать файл запускаемым и добавить впереди &lt;tt&gt;#!/bin/bash&lt;/tt&gt; (и пренебречь тем, что &lt;tt&gt;cmd.exe&lt;/tt&gt; успевает ругнуться на эту строку до очистки экрана), у нас получится следующий файл, работающий во всех трёх операционках (кодировка должна быть &lt;i&gt;Windows-1251&lt;/i&gt;):&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="bash"&gt;#!/bin/bash
:; @ECHO() { :;}; CLS() { clear; }; CHCP() { ENC=&amp;quot;$1&amp;quot;; }
@ECHO off
CHCP 1251
CLS
:; ECHO.() { echo $@ | iconv -f &amp;quot;CP$ENC&amp;quot;; }
ECHO. Всем привет&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;А вот дальше сложнее. Само меню организовано в оригинале так:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="php"&gt;SET /p opt=Введите цифру:

IF %opt%==1 GOTO dns_auto
IF %opt%==2 GOTO dnschange
IF %opt%==3 GOTO exit&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;В «баше» &lt;tt&gt;goto&lt;/tt&gt; (переход к метке) отсутствует и это проблема. Аналогов тоже нет. Единственное, что тут можно сделать — использовать вызов функций, но синтаксис в «бате» и «баше» сильно различается.&lt;/p&gt;
&lt;p&gt;Как быть? Во-первых, сэмулировать функцией команду &lt;tt&gt;SET&lt;/tt&gt;, во-вторвых, упростить это место, чтобы меньше было писать кода на «баше»:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="bash"&gt;:; SET() { shift; ECHO. -n &amp;quot;${@#*=}&amp;quot;; read -n1 &amp;quot;${1%%=*}&amp;quot;; echo; }
:; CALL() { eval &amp;quot;$(sed &amp;#039;s/%\(.*\)%/$\1/g&amp;#039; &amp;lt;&amp;lt;&amp;lt; &amp;quot;$1&amp;quot;)&amp;quot; 2&amp;gt;&amp;amp;-; }

SET /p opt=Введите цифру:
CALL :menu_%opt%&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Первая функция парсит команду &lt;tt&gt;SET&lt;/tt&gt; выводит строку после равно, ждёт ввода и записывает значение в имя переменной, указанной слева от равно.&lt;/p&gt;
&lt;p&gt;Вторая — заменяет &lt;tt&gt;CALL&lt;/tt&gt;. В ней &lt;tt&gt;%variable%&lt;/tt&gt; заменяется на &lt;tt&gt;$variable&lt;/tt&gt;, выполняется подстановка переменной и получившееся имя выполняется как команда или функция «баша». Конструкция &lt;tt&gt;2&amp;gt;&amp;amp;-&lt;/tt&gt; нужна, чтобы избежать вывода ошибки в ситуации, если пользователь введёт что-нибудь не то.&lt;/p&gt;
&lt;p&gt;Теперь надо как-то научиться определять функции так, чтобы их нормально «видел» и &lt;tt&gt;cmd.exe&lt;/tt&gt;, и «баш». В батнике функции — просто любое место программы, начинающееся с метки и заканчивающееся вызовом &lt;tt&gt;GOTO :EOF&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="php"&gt;:function_1
ECHO это якобы функция
GOTO :EOF&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;В «баше» то же самое могло бы выглядеть, например, так:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="bash"&gt;function_1() {
    echo это функция
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Как это объединить? Я придумал следующий подход:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="bash"&gt;:; GOTO() { :; };

GOTO ;#start
:function_1 (){
ECHO. это [якобы] функция
GOTO :EOF
:; }

:;#start&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;В первой строке определяется пустая функция для «баша», потому что эта часть синтаксиса бат-файла нам не нужна.&lt;/p&gt;
&lt;p&gt;Ниже идёт строка &lt;tt&gt;GOTO ;#start&lt;/tt&gt;. С точки зрения «баша» тут две конструкции — &lt;tt&gt;GOTO&lt;/tt&gt;, которая вызывает определённую выше пустую функцию и &lt;tt&gt;#start&lt;/tt&gt; — строка комментария, так как в«баше» с «решётки» начинаются комментарии.&lt;/p&gt;
&lt;p&gt;В «батнике» же эта же строка будет означать переход к метке с именем &lt;tt&gt;;#start&lt;/tt&gt;. Этот переход нужен нам, чтобы «обогнуть» строки, которые определены ниже, иначе &lt;tt&gt;cmd.exe&lt;/tt&gt; начнёт сразу их выполнять, а нам этого не нужно. Их нельзя «спрятать» ниже основной программы, так как в «баше» функции должны определены раньше их вызова.&lt;/p&gt;
&lt;p&gt;Что происходит дальше? С точки зрения &lt;tt&gt;cmd.exe&lt;/tt&gt; ниже расположена метка &lt;tt&gt;:function_1&lt;/tt&gt; (как показывают мои эксперименты, часть после пробела просто отбрасывается), потом тело функции, команда её завершения &lt;tt&gt;GOTO :EOF&lt;/tt&gt; и метка с именем &lt;tt&gt;:;}&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;С точки зрения «баша» там определяется функция с именем &lt;tt&gt;:function_1&lt;/tt&gt;, ниже идут вызовы уже определённых мною функций &lt;tt&gt;ECHO.&lt;/tt&gt; и &lt;tt&gt;GOTO&lt;/tt&gt;, а ещё ниже — уже знакомая нам пустая команда &lt;tt&gt;:&lt;/tt&gt; и фигурная скобка, завершающая тело функции.&lt;/p&gt;
&lt;p&gt;Соединяем всё вместе и получается следующая программа:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="bash"&gt;#!/bin/bash
:; @ECHO() { :;}; CLS() { clear; }; CHCP() { ENC=&amp;quot;$1&amp;quot;; }
@ECHO off
CHCP 1251
CLS

:; GOTO() { :; };
:; ECHO.() { echo $@ | iconv -f &amp;quot;CP$ENC&amp;quot;; }; PAUSE() { read; }; 
:; SET() { shift; ECHO. -n &amp;quot;${@#*=}&amp;quot;; read &amp;quot;${1%%=*}&amp;quot;; }
:; CALL() { eval &amp;quot;$(sed &amp;#039;s/%\(.*\)%/$\1/g&amp;#039; &amp;lt;&amp;lt;&amp;lt; &amp;quot;$1&amp;quot;)&amp;quot; 2&amp;gt;&amp;amp;-; }

GOTO ;#start

:menu_1 (){
ECHO. Пункт первый
GOTO :EOF
:; }

:menu_2 (){
ECHO. Пункт второй
GOTO :EOF
:; }

:;#start

SET /p opt=Введите цифру:
CALL :menu_%opt%&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Мой оппонент признал, что в споре я победил.&lt;/p&gt;
</description>
</item>

<item>
<title>Ненормальный цикл на «баше»</title>
<guid isPermaLink="false">118754</guid>
<link>https://bolknote.ru/all/nenormalny-cikl-na-bashe/</link>
<pubDate>Mon, 24 Apr 2023 20:25:17 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/nenormalny-cikl-na-bashe/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Сегодня в чате бывших коллег на фоне вопросов по одной из вакансий случилось обсуждение на тему что делать, если на собеседовании спросили как написать на «баше» цикл от одного до десяти, а ты не помнишь синтаксис и команду &lt;tt&gt;seq&lt;/tt&gt; тоже не знаешь.&lt;/p&gt;
&lt;p&gt;Предположим ты честно говоришь, что не помнишь, а тебя просят как-то выкрутиться теми знаниями, которые есть.&lt;/p&gt;
&lt;p&gt;Мой вариант:&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2023.04.24.1@2x.jpg" width="1000" height="281" alt="" /&gt;
&lt;/div&gt;
</description>
</item>

<item>
<title>👁 Глаз следящий</title>
<guid isPermaLink="false">118789</guid>
<link>https://bolknote.ru/all/4432/</link>
<pubDate>Sat, 05 Mar 2016 22:13:00 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/4432/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2016.03.05@2x.jpg" width="374" height="266" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Глаз, следящий за мышью в консоли&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Обновилась до версии 2.9 моя любимая программа-терминал &lt;i&gt;iTerm2&lt;/i&gt;. Изучая новые возможности, обнаружил нечто неожиданное — теперь в консоль &lt;a href="https://www.iterm2.com/images.html"&gt;можно выводить&lt;/a&gt; обычные графические изображения.&lt;/p&gt;
&lt;p&gt;Протокол довольно простой:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;ESC ] 1337 ; File = [необязательные параметры] : изображение в формате base64 ^G&lt;/code&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;Решил немного с ним побаловаться, результат на скриншоте — небольшая программа на «баше» — &lt;a href="https://github.com/bolknote/shellgames/blob/master/eye.bash"&gt;глаз, который следит за указателем мыши&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Пришлось разобраться с тем как вообще получают координаты мыши в консоли, плюс вспомнить школьную геометрию. Синусы, косинусы, вот это всё, неявно вычисляются через &lt;i&gt;awk&lt;/i&gt; и используются для определения где нужно рисовать зрачок.&lt;/p&gt;
&lt;p&gt;Чем дальше курсор находится от глаза, тем больше событий мыши получает консоль во время перемещений по окружности вокруг него. Из-за этого образуется некая инерционность слежения, которую я стал было корректировать, но потом убрал этот код — инерция придаёт какое-то интересное подобие жизни.&lt;/p&gt;
&lt;p&gt;Для запуска требуется &lt;i&gt;iTerm2&lt;/i&gt; 2.9 и выше и &lt;i&gt;Imagemagick&lt;/i&gt;.&lt;/p&gt;
</description>
</item>

<item>
<title>Как работает Bashfuck</title>
<guid isPermaLink="false">133178</guid>
<link>https://bolknote.ru/all/4251/</link>
<pubDate>Wed, 10 Dec 2014 21:44:00 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/4251/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Думаю, по горячим следам надо описать как работают мои &lt;a href="/2014/12/09/~4248"&gt;&lt;i&gt;Bashfuck&lt;/i&gt;&lt;/a&gt; и &lt;a href="/2014/12/10/~4250"&gt;&lt;i&gt;Bashfuck-2&lt;/i&gt;&lt;/a&gt;. Пока ещё сам детально помню.&lt;/p&gt;
&lt;p&gt;Поскольку буквы и цифры использовать запрещено, все имена переменных состоят исключительно из подчёркиваний — это единственный вариант в «Баше» в таком случае. Чтобы что-то напечатать, сначала надо получить какие-то буквы.&lt;/p&gt;
&lt;p&gt;К счастью, переменная с именем, состоящим из одного подчёркивания содержит полный путь к интерпретатору, которым был запущен наш скрипт. Поскольку путь может отличаться, а название интерпретатора — нет, путь надо удалить, оставив только слово «&lt;i&gt;bash&lt;/i&gt;». Это делается в обоих случая в первой строке:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;# Удаляем из переменной $_ всё до последнего слеша
__=${_##*/}&lt;/code&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;Теперь у нас есть четыре буквы «&lt;i&gt;b&lt;/i&gt;», «&lt;i&gt;a&lt;/i&gt;», «&lt;i&gt;s&lt;/i&gt;» и «&lt;i&gt;h&lt;/i&gt;». Из имеющегося надо как-то получить недостающее. Тут нам помогает следующий факт: можно запускать что угодно, по имени, которое содержится в переменной.&lt;/p&gt;
&lt;p&gt;Далее оба скрипта пытаются составить в одной из переменных команду «&lt;i&gt;base64&lt;/i&gt;», чтобы передав ей на вход строку, получить недостающие буквы. В самом деле, передавая на вход разные строки и пропуская их по нескольку раз через «&lt;i&gt;base64&lt;/i&gt;» команду, можно получить весь английский алфавит:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;# bash тут — строка, которую мы уже получили
$ base64&amp;lt;&amp;lt;&amp;lt;bash
YmFzaAo=
$ base64&amp;lt;&amp;lt;&amp;lt;bash | base64
WW1GemFBbz0K&lt;/code&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;Например, в полученных строках некоторые буквы нам вполне интересны: «&lt;i&gt;Hell&lt;b&gt;o&lt;/b&gt; &lt;b&gt;wo&lt;/b&gt;rld&lt;/i&gt;». Но как получить слово &lt;i&gt;base64&lt;/i&gt;? С цифрами проще: имея строки разной длины и арифметические операции можно получить нужное:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;# Переменная __ содержит слово bash
__=bash
# Очень просто получить цифру четыре: надо измерить длину строки:
$ echo ${#__}
4
# Любым похожим путём получаем двойку, прибавляем к четвёртке и у нас есть 6
$ echo $((${#__} + 2))
6&lt;/code&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;Поскольку типы переменных «Баш» не особо-то различает, склеить всё остальное труда не представляет. Но нужно ещё откуда-то получить букву «&lt;i&gt;e&lt;/i&gt;». Тут дорожки этих двух скриптов расходятся. Первый работает так: составляя из имеющихся букв команду «&lt;i&gt;hash&lt;/i&gt;», запускает её и получает следующую строку:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;$ hash
hash: hash table empty&lt;/code&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;Второй действует интереснее. Есть такой синтаксис для команд, которые на вход принимают только файл: можно передать вывод другой команды особым образом и интерпретатор подставит в параметр специальное имя псевдофайла из которого можно прочитать упомянутый вывод.&lt;/p&gt;
&lt;p&gt;Если использовать такой синтаксис с любой командой, которая принимает не файл, а строку, то строку и получим (цифры будут меняться от запуска к запуску, остальная строка останется неизменной):&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;# пробуем вывести на печать
$ echo &amp;lt;(:)
/dev/fd/63&lt;/code&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;Нам это значение нужно в переменной и с присвоением этот трюк тоже сработет.&lt;/p&gt;
&lt;p&gt;В том и другом скрипте нужную букву мы получили и можем собрать нужное имя без проблем. Для этого воспользуемся следующей конструкцией, которая позволяет выбирать подстроки из переменных:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;# переменная теперь содержит что-то вроде /dev/fd/xx
___=&amp;lt;(:)
# выбираем третий символ (отсчёт с нуля):
echo ${___:2:1}&lt;/code&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;Вместо двойки и единицы можно подставить переменные, которые эти числа содержат, либо вычислить их по ходу дела. Во втором примере применяется ещё и другая техника —  поскольку некоторые числа из подручных переменных вычислять сложно, я срезаю некоторое количество букв слева и справа, чтобы добраться до нужной буквы:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;# переменная, где нужная мне буква в середине слова
v=sed
# так можно срезать последнюю букву
echo ${v%?}
# а так —  первую
echo ${v#?}&lt;/code&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;По большому счёту, это всё. Используется ещё несколько приёмов, но для понимания происходящего осталось пояснить только ещё одну вещь. В четвёртом «Баше», который требуется для работы обоих скриптов, есть ещё такой специальный синтаксис, который позволяет менять регистр букв. Это позвояет не заморачиваться с тем, в каком регистре получаются отдельные буквы и првести всё к нужному ближе к концу:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;v=&amp;#039;heLLo WORld&amp;#039;
# всё к нижнему (будет hello world)
echo ${v,,}
# только первую —  к верхнему (будет HeLLo WORld)
echo ${v^}&lt;/code&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;Собранную строку осталось вывести на экран. Для этого в том же коде я попутно собираю из получающихся букв ещё и строку «&lt;i&gt;cat&lt;/i&gt;» (что на одну букву меньше «&lt;i&gt;echo&lt;/i&gt;», кода получается меньше) и с помощью этой команды получаю нужный результат:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;c=cat
v=&amp;#039;Hello world&amp;#039;
# Выведет Hello world
$c&amp;lt;&amp;lt;&amp;lt;$v&lt;/code&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;Можно, кстати, попробовать ещё задействовать функции, благо их объявление алфавитных символов не требует, а их имена могут подержать не только подчёркивания (но и, например, «собаку», что даёт бо́льшую свободу), но третий вариант я уже делать не буду, надоело.&lt;/p&gt;
</description>
</item>

<item>
<title>Удаляем расладку «U.S. English» из «Мака»</title>
<guid isPermaLink="false">133884</guid>
<link>https://bolknote.ru/all/3724/</link>
<pubDate>Sat, 25 Aug 2012 00:48:00 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/3724/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Артём Поликарпов &lt;a href="https://web.archive.org/web/20120827053608/http://artpolikarpov.ru/2012/08/24/1/"&gt;написал&lt;/a&gt; рецепт как можно удалить из «Мака» раскладку «U.S. English». Она очень мешается и совершенно не нужна, если поставить великолепную &lt;a href="http://ilyabirman.ru/projects/typography-layout/"&gt;раскладку Ильи Бирмана&lt;/a&gt; (кстати, если вы почему-то ей не пользуетесь, то вы делаете большую ошибку).&lt;/p&gt;
&lt;p&gt;Но рецепт Артёма мне не нравится тем, что для его выполнения приходится иметь у себя редактор &lt;i&gt;Xcode&lt;/i&gt;, который ещё и несколько гигабайт весит. Поэтому я, как водится, &lt;a href="https://github.com/bolknote/shellgames/blob/master/us_layout_remover.sh"&gt;написал скрипт&lt;/a&gt;, который нужно выполнить из «Терминала» (после его выполнения придётся опять залогиниться в систему) и ненужной раскладки уже не будет.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2012.08.24.png" width="297" height="112" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Ничего ненужного&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Какое счастье!&lt;/p&gt;
&lt;p&gt;Проще всего скрипт запускать из «Терминала» вот так:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="bash"&gt;bash  &amp;lt;(curl -fsSkL raw.github.com/bolknote/shellgames/master/us_layout_remover.sh)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Чтобы вернуть всё обратно достаточно запустить программу ещё раз.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Добавлено позднее&lt;/i&gt;: удалению раскладки &lt;a href="https://bolknote.ru/all/3724/"&gt;может мешать&lt;/a&gt; &lt;i&gt;Punto Switcher&lt;/i&gt;.&lt;/p&gt;
</description>
</item>


</channel>
</rss>