bash
Ошмётки в консоли
Как известно, много лет назад «Эпл» перешла с процессоров «Интел» на собственные, основанные на архитектуре «АРМ». Процессоры несовместимы, однако бинарные программы, скомпилированные под «Интел», продолжают работать — в «МакОС» встроен специальный транслятор, который обеспечивает такую возможность.
Много лет я таскаю с собой различные утилиты, которые при переходе с одного «Макбука» на другой автоматически копируются при помощи встроенной в ОС процедуры миграции. Однако некоторое время назад я занялся тем, что с помощью brew перевёл всё это бинарное хозяйство на «АРМ».
По пути у меня
Я всю голову сломал, пытаясь понять что же произошло, даже переставил себе iTerm2, думал дело в нём, но не помогло. Подумал, что может у меня
Тут я
Оказывается библиотека readline, отвечающая за редактирование текста в командной строке, неправильно считает длину строки, если в ней есть управляющие символы, — например, задающие цвет. Чтобы всё работало как надо, их надо обрамлять специальными последовательностями \[ и \]. Если я
В общем, я заменил приглашение с
PS1='\e[33;1m\u: \e[31m\W$(__git_ps1)\e[0m \$ 'на
PS1='\[\e[33;1m\]\u:\[\e[0m\] \[\e[31m\]\W$(__git_ps1)\[\e[0m\] \$ 'и всё заработало как надо.
Bash HTTPd
У писателя Леонида Каганова, который в последние годы ушёл в айти, началась
Я ему сегодня утром пытался хоть
В процессе там понадобился
Обошлись
В общем, мне стало
В процессе код стал занимать меньше места (моя минифицированная версия на 25 байт короче), научился обрабатывать имена, содержащие пробелы и национальные символы и заработал не только под «Линуксом», но и под «Макосью».
Bash The Wumpus
Образовалась на днях у меня в голове доброкачественная идея — сделать
Директории будут комнатами, ходить
Для реализации выбрал тот же классический квест
В соответствии с идеей, помещения у меня представлены директориями, а переходы между ними — символическими ссылками. Соответственно, Вампус и прочие опасности, — ямы и летучие мыши, стали файлами.
В первой версии у меня всё было организовано обычными командами. Кроме упомянутой cd, вполне естественным способом заработали ls и pwd, а так же команда rm, которая уничтожала
К сожалению, это было слишком похоже на «молдавский вирус» («ввиду общей отсталости развития высоких технологий нашей страны, пожалуйста, сотрите сами несколько самых нужных вам файлов, а затем разошлите меня по почте своим друзьям»), пришлось добавить командам
Сначала я сделал проверки через trap сигнала DEBUG и обработку произошедшего через скрипт, который запускается из переменной подсказки PS1, но в итоге пришлось подменить ряд команд алиасами и вызовами функций.
Чтобы сохранить вайб консоли семидесятых, сообщения в игровом процессе и инструкцию я взял из оригинальной игры и оставил всё в верхнем регистре, как и в оригинале.
Поскольку команды подаются в консоли, можно выиграть почти сразу, если знать парочку фокусов. Я постарался осложнить их использование, но все возможности не закрыл, это противоречит изначальной идее.
Игра, как обычно, выложена на «Гитхабе».
cmd.sh ★
Я тут случайно в спор ввязался — можно ли переписать
Речь шла о вполне определённом файле, там запрограммировано небольшое меню и в зависимости от выбранного пункта запускается та или иная, одинаковая для всех ОС, последовательность команд.
Мой собеседник мне не верил, когда я утверждал, что это вполне возможно, и требовал доказательств.
Что ж. Основная моя идея была в том, чтобы заменить команды батника на вызовы
То, что мне предстояло адаптировать начиналось вполне стандартно:
@ECHO off
CHCP 1251
CLSЧто тут происходит? Выключается вывод команд на экран (при адаптации это можно игнорировать), ставится однобайтовая кодировка CP1251 (это хорошо бы учесть) и очищается экран.
Поскольку «баш» этих команд не знает, надо определить три функции, спрятав их от cmd.exe. Сделать это несложно. Команду «двоеточие» cmd.exe трактует как начало метки и на дальнейшее не реагирует, а «баш» считает её пустой командой, которую можно точкой с запятой отделить от строки, которую мы хотим спрятать:
:; @ECHO() { :;}; CLS() { clear; }; CHCP() { ENC="$1"; }Следующее, чему надо научиться — выводить текст в указанной в батнике кодировке. Это просто:
:; ECHO.() { echo $@ | iconv -f "CP$ENC"; }Если теперь сделать файл запускаемым и добавить впереди #!/bin/bash (и пренебречь тем, что cmd.exe успевает ругнуться на эту строку до очистки экрана), у нас получится следующий файл, работающий во всех трёх операционках (кодировка должна быть
#!/bin/bash
:; @ECHO() { :;}; CLS() { clear; }; CHCP() { ENC="$1"; }
@ECHO off
CHCP 1251
CLS
:; ECHO.() { echo $@ | iconv -f "CP$ENC"; }
ECHO. Всем приветА вот дальше сложнее. Само меню организовано в оригинале так:
SET /p opt=Введите цифру:
IF %opt%==1 GOTO dns_auto
IF %opt%==2 GOTO dnschange
IF %opt%==3 GOTO exitВ «баше» goto (переход к метке) отсутствует и это проблема. Аналогов тоже нет. Единственное, что тут можно сделать — использовать вызов функций, но синтаксис в «бате» и «баше» сильно различается.
Как быть?
:; SET() { shift; ECHO. -n "${@#*=}"; read -n1 "${1%%=*}"; echo; }
:; CALL() { eval "$(sed 's/%\(.*\)%/$\1/g' <<< "$1")" 2>&-; }
SET /p opt=Введите цифру:
CALL :menu_%opt%Первая функция парсит команду SET выводит строку после равно, ждёт ввода и записывает значение в имя переменной, указанной слева от равно.
Вторая — заменяет CALL. В ней %variable% заменяется на $variable, выполняется подстановка переменной и получившееся имя выполняется как команда или функция «баша». Конструкция 2>&- нужна, чтобы избежать вывода ошибки в ситуации, если пользователь введёт
Теперь надо
:function_1
ECHO это якобы функция
GOTO :EOFВ «баше» то же самое могло бы выглядеть, например, так:
function_1() {
echo это функция
}Как это объединить? Я придумал следующий подход:
:; GOTO() { :; };
GOTO ;#start
:function_1 (){
ECHO. это [якобы] функция
GOTO :EOF
:; }
:;#startВ первой строке определяется пустая функция для «баша», потому что эта часть синтаксиса
Ниже идёт строка GOTO ;#start. С точки зрения «баша» тут две конструкции — GOTO, которая вызывает определённую выше пустую функцию и #start — строка комментария, так как в«баше» с «решётки» начинаются комментарии.
В «батнике» же эта же строка будет означать переход к метке с именем ;#start. Этот переход нужен нам, чтобы «обогнуть» строки, которые определены ниже, иначе cmd.exe начнёт сразу их выполнять, а нам этого не нужно. Их нельзя «спрятать» ниже основной программы, так как в «баше» функции должны определены раньше их вызова.
Что происходит дальше? С точки зрения cmd.exe ниже расположена метка :function_1 (как показывают мои эксперименты, часть после пробела просто отбрасывается), потом тело функции, команда её завершения GOTO :EOF и метка с именем :;}.
С точки зрения «баша» там определяется функция с именем :function_1, ниже идут вызовы уже определённых мною функций ECHO. и GOTO, а ещё ниже — уже знакомая нам пустая команда : и фигурная скобка, завершающая тело функции.
Соединяем всё вместе и получается следующая программа:
#!/bin/bash
:; @ECHO() { :;}; CLS() { clear; }; CHCP() { ENC="$1"; }
@ECHO off
CHCP 1251
CLS
:; GOTO() { :; };
:; ECHO.() { echo $@ | iconv -f "CP$ENC"; }; PAUSE() { read; };
:; SET() { shift; ECHO. -n "${@#*=}"; read "${1%%=*}"; }
:; CALL() { eval "$(sed 's/%\(.*\)%/$\1/g' <<< "$1")" 2>&-; }
GOTO ;#start
:menu_1 (){
ECHO. Пункт первый
GOTO :EOF
:; }
:menu_2 (){
ECHO. Пункт второй
GOTO :EOF
:; }
:;#start
SET /p opt=Введите цифру:
CALL :menu_%opt%Мой оппонент признал, что в споре я победил.
Ненормальный цикл на «баше»
Сегодня в чате бывших коллег на фоне вопросов по одной из вакансий случилось обсуждение на тему что делать, если на собеседовании спросили как написать на «баше» цикл от одного до десяти, а ты не помнишь синтаксис for и команду seq тоже не знаешь.
Предположим ты честно говоришь, что не помнишь, а тебя просят
Мой вариант:
Надпись в «Гитхабе» ★
С тех пор как в первый раз увидел панель активности «Гитхаба», хочу на ней
И вот, годы спустя, я наконец сподобился сделать скрипт, чтобы автоматизировать процесс и написать себе там слово «ПРИВЕТ».
Скрипт переводит подготовленную картинку размером 52×7 пискелей в нужную интенсивность коммитов и распределяет их по датам. Для надписи я использовал шрифт silkscreen, русифицированный
Если захотите себе такую же, вам понадобится так же bash, git и утилиты из набора ImageMagick. Создаёте пустой репозиторий на «Гитхабе», привязываете его к локальному, запускаете мою утилиту с картинкой и любуетесь изображением на панели активности.
Алгол и Баш
Удивительно, я и не догадывался, что иногда употребляю ключевые слова родом
Оказывается автор командной оболочки bsh Стивен Борн притащил ключевые слова IF/FI и CASE/ESAC прямиком из «Алгола». Позже оттуда они попали в более известный сейчас bash, на котором я нередко пишу.
Более того, Стивен Борн по всей видимости насколько крепко фанател по этому языку, что специальными макросами превратил Си, на котором написал bsh, в некое подобие «Алгола» (исходники есть в интернете).
Если скачать себе пару заголовочных файлов (и выкинуть из них всё то, что мешает компиляции), то можно и сейчас попробовать этот макроязык в деле (это я пузырьковую сортировку написал):
#pragma GCC diagnostic ignored "-Wimplicit-int"
#pragma GCC diagnostic ignored "-Wreturn-type"
#include "mac.h"
#include "mode.h"
#include <stdio.h>
bubbleSort(arr, n)
INT arr[], n;
BEGIN
INT i, j;
FOR i = 0; i < n - 1; i++
DO FOR j = 0; j < n - i - 1; j++
DO IF arr[j] > arr[j + 1]
THEN arr[j] = arr[j] - arr[j+1];
arr[j+1] = arr[j] + arr[j+1];
arr[j] = arr[j+1] - arr[j];
FI
OD
OD
END
printArray(arr, n)
INT arr[], n;
BEGIN
INT i;
FOR i = 0; i < n; i++
DO
printf("%d ", arr[i]);
OD
printf("\n");
END
main()
BEGIN
INT arr[] = { 0xFE, 0xED, 0xBE, 0xEF };
INT n = 1[&arr] - arr;
printArray(arr, n);
bubbleSort(arr, n);
printArray(arr, n);
ENDПримерно так выглядят исходники bsh. Единственное моё добавление — BEGIN и END, которые Борн для описания тела функций не использует, но зато в «Алголе» принято делать именно так.
Кстати (век живи — век учись), такое неординарное объявление функций, как у меня в листинге (а я подсмотрел его в исходниках bsh), — как оказалось, устаревший синтаксис Си, причём он до сих пор поддерживается компиляторами.
«99 бутылок» на баше без цикла
Когда я только начал программировать, все интерпретаторы, которые мне попадались в то далёкое время, интерпретировали программу построчно. Недавно разговаривали на эту тему с одним из приятелей, который буквально был в шоке, когда случайно обнаружил, что популярная оболочка bash работает именно таким образом.
Мне кажется совершенно естественным, что такой способ интерпретации должен дожить и до наших дней, он же очень простой в реализации и для многих вещей его вполне достаточно.
#!/bin/bash
len=$(wc -c<"$0"); : https://bolknote.ru 2021
echo -e "99 bottles of beer on the wall, 99 bottles of beer.
Take one down and pass it around, 98 bottles of beer on the wall.\n"
: ${i:=99}; ((--i)) && (grep -B5 -m1 ^G "$0" |
sed "s/9[8]/$(($i-1))/g;s/9[9]/$i/g;s/ [0] / no /;s/\([1] b[^s]*\)s/\\1/g" >> "$0") ||
(echo 'No more bottles of beer on the wall, no more bottles of beer.
Go to the store and buy some more, 99 bottles of beer on the wall.';truncate -s "$len" "$0")
:;Пока разговаривали, у меня возникла смешная идея — попробовать написать считалочку «99 бутылок пива…» без циклов, на принципе дописывания кода, чтобы строки добавлялись в файл программы по мере интерпретации.
Результат чуть выше. Так как bash местами довольно сложен для понимания, попробую позже (если не заленюсь) сделать разбор странно выглядящих мест этой программы отдельным постом.
Говорящие часы
По причинам, далёким от рациональных, захотелось мне вчера сколхозить для себя говорилку времени. Простой вариант проговаривания цифр показался очень скучным, сразу вспомнились лебедевские часы «Вербариус», где одно и то же время каждый раз пишется
На сайте «Студии Лебедева», в разделе часов «Вербариус» есть языковые файлы, три из которых — для русского, английского и французского выгружены в виде обычных экселевских таблиц. Их легко преобразовать в формат CSV при помощи приложения «Намберс» или всем знакомого «Экселя».
В получившемся файле много пустых полей и лишних пробельных символов, которые будут мешать, их легко удалить утилитой командной строки sed:
sed -i '' -E "s/; +| +;/;/g; s/;+/;/g; s/;[ "$'\r'"]*$//;" ~/Downloads/russian.csvУ получившегося файла очень простой формат — сначала идёт время без ведущего нуля, потом — варианты для произношения, разделённые точкой с запятой. На мой взгляд, для поиска нужной строки и выбора случайного вариант для произношения лучше всего подойдёт утилита awk.
Если направить её вывод маковской утилите say, то говорящие часы готовы:
awk -F\; "BEGIN{srand}/^$(date +%k:%M|xargs)/{print \$(int(2+rand*(NF-1))); exit;}" \
~/Downloads/russian.csv | xargs sayЯ их пока вызываю из командной строки коротким алиасом t, но если понравится, настрою как службу, с вызовом через горячую клавишу.
Как проверить не битая ли картинка
По работе понадобилось из командной строки проверить несколько тысяч картинок на корректность — со смертью носителя часть картинок разрушилась. Чтобы их найти, придумался такой незамысловатый способ:
convert path_to_image null: 2>&- || echo File is corruptedЕсли картинка path_to_image разрушена, то этот однострочник выведет «File is corrupted».
Утилита convert входит в состав пакета «Imagemagick» и достаточно распространена.
Принцип понятен, наверное: я прошу утилиту сконвертировать файл, указанный первым параметром, в псевдоформат NULL (указан до двоеточия во втором параметре) — это специальный формат используется, когда результат конвертации не нужен — обычно для замера производительности.
Входная картинка полностью разбирается кодеком, если это не удаётся сделать, то convert поругается в поток вывода ошибок (который я закрыл) и вернёт код возврата отличный от нуля, на что среагируют две вертикальные черты, которые запустят вторую команду.
Конечно, картинка должна быть в формате, который утилита понимает, но всё хоть немного распростанённое туда входит.
Bashfuck-3
Вчера весь день болела голова и я, чтобы хоть
Цель, напомню, написать программу, которая делает
В свежем варианте самое главное новшевство — использование функций.
В «баше» с именами переменных всё чересчур строго, если не использовать буквы и цифры остаются доллар и подчёркивание, смотрится однообразно
А вот с функциями веселее, я использовал в именах точки и тире, и закодировал при помощи азбуки Морзе результат работы каждой функции. Например функция, которая генерирует букву «w» называется «.__» (то есть
В этот раз я использовал более разнообразный набор свежевыдуманных трюков для получения букв. Большинство букв набрал из вывода команды df (показывает наличие места на смонтированных устройствах), первая строка вывода содержит заголовки полей (и разнообразных букв) и мало отличается от системы к системе.
Имя этой команды легко получается из конструкции перенаправления
Ещё немного помогла специальная переменная «минус» (да, у неё имя такое), в ней отображаются установленные флаги, в скриптах там всегда две буквы — «hB», их я тоже использовал. Так же мне нужны были цифры, чтобы получать буквы из строк по индексу (благо инструкции работы со строками делаются специальными значками, а не именованными функциями, как в большинстве языков).
С цифрами особых проблем не было. Так, например измерением длины значения переменной «минус» (длина измеряется символом «решётка») получается цифра два, очень удобно. Цифра «один» получается измерением длины значения другой переменной — кода возврата последней команды (её имя — «вопрос»), остальные нужные цифры получались комбинацией этих двух.
Из всего вышеописанного получились все буквы, кроме «r» и «w». Первую я получил, запустив на выполнение ls /bin/?m — по маске гарантированно находится файл команды удаления /bin/rm, её имя содержит искомую букву.
Для получения второй воспользовался командой «tr» и идеей, похожей на реализацию ROT13 на «баше» — подобрал диапазоны из имеющихся в моём распоряжении букв так, чтобы одна подходящая буква сдвинулась нужным мне образом — стала буквой «w».
Скриптование меню в статус-баре
В «Маке» очень нехватает одной вещи — лёгкого создания собственных меню
Если кому интересно, то последовательность его прикручивания к системе примерно такова (bolk — моё имя пользователя и требуется установленный brew):
mkdir -p /usr/local/Cellar/ScriptableStatusBar/0.1/bin/
mv ~/Downloads/ScriptableStatusBar-release/usr/local/bin/sbar !:2
mv ~/Downloads/ScriptableStatusBar-release/Applications/
/usr/local/Cellar/ScriptableStatusBar/0.1
brew link ScriptableStatusBar
open /usr/local/Cellar/ScriptableStatusBar/0.1/Applications/
# Тут надо утянуть открывшееся приложение в «Объекты входа»
# и ещё запустить его в открывшемся окне, разрешив ему в принципе запускатьсяОчень неудобно и несколько недоделано. Хотелось бы, чтобы из шелла можно было добавить/удалить пункт меню и сменить иконку. Сейчас это тоже можно, но полной переинициализацией и, кроме того, убъёшься всё экранировать.
Вооружившись несложной инструкцией, делаем несколько магических пассов:
cat>~/lockkeyboard.sh<<LOCK
#!/bin/ksh
kext=/System/Library/Extensions/AppleUSBTopCase.kext/Contents/PlugIns/AppleUSBTCKeyboard.kext/
case "$1" in
unlock )
/sbin/kextload "$kext"
;;
lock )
/sbin/kextunload "$kext"
;;
esac
LOCK
sudo chown root:staff ~/lockkeyboard.sh
sudo chmod 750 ~/lockkeyboard.sh
sudo cp /dev/stdin /private/etc/sudoers.d/lockkeyboard<<SUDO
bolk ALL= NOPASSWD: /Users/bolk/lockkeyboard.sh
SUDO
sbar set locker ?\
'Lock:/usr/bin/sudo /Users/bolk/lockkeyboard.sh lock'\
'Unlock:/usr/bin/sudo /Users/bolk/lockkeyboard.sh unlock'\
'Quit:/usr/local/bin/sbar remove locker'И получаем малофункциональную такую менюшечку для блокировки клавиатуры (кстати и увы, если компьютер с заблокированной клавиатурой, у вас уйдёт в блокировку
В принципе можно даже сэмулировать защёлкивание замка и смену пунктов меню «Lock» на «Unlock» и обратно (для этого нужно просто пересоздавать меню после каждой из этих команд с другими пунктами и другим замочком), но это ещё полэкрана костылей, которые мне совсем не хочется на вас вываливать.
Кстати, пункты в меню добавляются в произвольном порядке — программе совершенно плевать в каком порядке вы их задали в параметрах.
👁 Глаз следящий
Обновилась до версии 2.9 моя любимая
Протокол довольно простой:
ESC ] 1337 ; File = [необязательные параметры] : изображение в формате base64 ^GРешил немного с ним побаловаться, результат на скриншоте — небольшая программа на «баше» — глаз, который следит за указателем мыши.
Пришлось разобраться с тем как вообще получают координаты мыши в консоли, плюс вспомнить школьную геометрию. Синусы, косинусы, вот это всё, неявно вычисляются через awk и используются для определения где нужно рисовать зрачок.
Чем дальше курсор находится от глаза, тем больше событий мыши получает консоль во время перемещений по окружности вокруг него.
Для запуска требуется iTerm2 2.9 и выше и Imagemagick.
Подпилил переподсоединялку вайфая
Чуть поменял «переподсоединялку вайфая» для Мака — теперь пингуется не 8.8.8.8 (это ДНС Гугла), а адрес гейта, что более надёжно. Правда с конца октября, когда я её написал много воды утекло — вайфай у меня отваливается теперь очень редко, уж не знаю что изменилось.
Переподсоединялка вайфая

Вышло очередное обноление «Эль Капитана» на «Маке», а проблема с вайфаем на «Макбуках Про» так никуда и не делась. Я планирую
В общем, сделал себе на «Баше» утилиту переподключающую вайфай при пропадании пингов до 8.8.8.8 (это ДНС «Гугла»). Сегодня уже целый день её использую, так гораздо комфортнее.
Где это я был?

Нацарапал утилитку на «Баше», которая помогает узнать к каким
Как работает Bashfuck
Думаю, по горячим следам надо описать как работают мои Bashfuck и
Поскольку буквы и цифры использовать запрещено, все имена переменных состоят исключительно из подчёркиваний — это единственный вариант в «Баше» в таком случае. Чтобы
К счастью, переменная с именем, состоящим из одного подчёркивания содержит полный путь к интерпретатору, которым был запущен наш скрипт. Поскольку путь может отличаться, а название интерпретатора — нет, путь надо удалить, оставив только слово «bash». Это делается в обоих случая в первой строке:
# Удаляем из переменной $_ всё до последнего слеша
__=${_##*/}Теперь у нас есть четыре буквы «b», «a», «s» и «h». Из имеющегося надо
Далее оба скрипта пытаются составить в одной из переменных команду «base64», чтобы передав ей на вход строку, получить недостающие буквы. В самом деле, передавая на вход разные строки и пропуская их по нескольку раз через «base64» команду, можно получить весь английский алфавит:
# bash тут — строка, которую мы уже получили
$ base64<<<bash
YmFzaAo=
$ base64<<<bash | base64
WW1GemFBbz0KНапример, в полученных строках некоторые буквы нам вполне интересны: «Hello world». Но как получить слово base64? С цифрами проще: имея строки разной длины и арифметические операции можно получить нужное:
# Переменная __ содержит слово bash
__=bash
# Очень просто получить цифру четыре: надо измерить длину строки:
$ echo ${#__}
4
# Любым похожим путём получаем двойку, прибавляем к четвёртке и у нас есть 6
$ echo $((${#__} + 2))
6Поскольку типы переменных «Баш»
$ hash
hash: hash table emptyВторой действует интереснее. Есть такой синтаксис для команд, которые на вход принимают только файл: можно передать вывод другой команды особым образом и интерпретатор подставит в параметр специальное имя псевдофайла из которого можно прочитать упомянутый вывод.
Если использовать такой синтаксис с любой командой, которая принимает не файл, а строку, то строку и получим (цифры будут меняться от запуска к запуску, остальная строка останется неизменной):
# пробуем вывести на печать
$ echo <(:)
/dev/fd/63Нам это значение нужно в переменной и с присвоением этот трюк тоже сработет.
В том и другом скрипте нужную букву мы получили и можем собрать нужное имя без проблем. Для этого воспользуемся следующей конструкцией, которая позволяет выбирать подстроки из переменных:
# переменная теперь содержит что-то вроде /dev/fd/xx
___=<(:)
# выбираем третий символ (отсчёт с нуля):
echo ${___:2:1}Вместо двойки и единицы можно подставить переменные, которые эти числа содержат, либо вычислить их по ходу дела. Во втором примере применяется ещё и другая техника — поскольку некоторые числа из подручных переменных вычислять сложно, я срезаю некоторое количество букв слева и справа, чтобы добраться до нужной буквы:
# переменная, где нужная мне буква в середине слова
v=sed
# так можно срезать последнюю букву
echo ${v%?}
# а так — первую
echo ${v#?}По большому счёту, это всё. Используется ещё несколько приёмов, но для понимания происходящего осталось пояснить только ещё одну вещь. В четвёртом «Баше», который требуется для работы обоих скриптов, есть ещё такой специальный синтаксис, который позволяет менять регистр букв. Это позвояет не заморачиваться с тем, в каком регистре получаются отдельные буквы и првести всё к нужному ближе к концу:
v='heLLo WORld'
# всё к нижнему (будет hello world)
echo ${v,,}
# только первую — к верхнему (будет HeLLo WORld)
echo ${v^}Собранную строку осталось вывести на экран. Для этого в том же коде я попутно собираю из получающихся букв ещё и строку «cat» (что на одну букву меньше «echo», кода получается меньше) и с помощью этой команды получаю нужный результат:
c=cat
v='Hello world'
# Выведет Hello world
$c<<<$vМожно, кстати, попробовать ещё задействовать функции, благо их объявление алфавитных символов не требует, а их имена могут подержать не только подчёркивания (но и, например, «собаку», что даёт бо́льшую свободу), но третий вариант я уже делать не буду, надоело.
Bashfuck-2
Попробовал несколько иной способ сбора строки «Hello world» в Bashfuck. Получилось, работает. В предыдущей версии один из читателей жаловался, что у него не запустилось, я тут подумал, что возможно версия «Баша» не та — требуется четвёртая, разумеется.
Вот другой вариант сбора строки:
__=${_##*/} ___=${#__} ______=${__::$(($___-${#___}))} ____=$((${#___}+${#___}))
_____=<(:) ___=$______${_____:$____:${#___}}$(($___+$____))$___
__=${__:(-${#____})}${_____:$____:${#____}} ____=`$___<<<$___|$___`
__=$__${____:$((${#______}+${#__})):$((${#______}^${#__}))} __=$__${__#??}
_______=${____:(-${#__})}
______=`$___<<<$__` __=$__${______#??????} __="${__%?} ${____::$((${#______}/${#__}))}"${__#????}
______=${#___} ____=`$___<<<$____|$___` __=${__%?}${____:$((${#___}+${#___})):$______}
__=${__%????}${_____:${#______}:${#______}} __=${__,,}
_______=${_______::${#______}}${___:${#______}:${#______}}$($___<<<$______|$___)
_______=${_______::$((${#____}/${#__}))};${_______,,}<<<${__^}Надо будет выбрать время, написать как оно работает.
Bashfuck
«…fuck» — это не ругательство, а развлечение, навеянное знаменитым языком программирования «Brainfuck». Практического смысла никакого, правила просты — написать программу
JSFuck у меня в блоге был, PHPFuck — тоже, был даже совмещённый в одной программе JSFuck и Brainfuck, почему бы не попробовать сделать то же на «Баше»?
__=${_##*/} ___=${#__}
__=($__ $(${__:$(($___-${#___}))}${__:${#___}:$___}) $__)
____=${__::$((${#__}-${#___}))}${__[$___]::${#___}}${#__[@]}${#__}
_____=$($____<<<${__[@]}) ______=${_____:${#__[${#__}]}:${#___}}
______=${______,}${__[${#_}]:${#___}:${#___}}${__[$(($___-${#___}))]:${#_}:${#___}}
_______=$($____<<<$_____)
____=${__[${#______}]:${#______}:${#___}} ____=$____$____
__=${__[${#_}]:${#______}}${__[$___]:${#_}:${#___}}$____${_____:$((${#__[@]}+${#__[$___]})):${#___}}
__=$__' '${_______::${#___}}${__:$___}${_____:$((${#_____}>>${#___})):${#___}}
__=$__${____:${#___}}${_______:$(($___+${#______})):${#___}} __=${__,,}
$______<<<${__^}Сказано — сделано, собственно. Программа на «Баше», что выше, выводит фразу «Hello world», её исходники можно свободно скачать с «ГитХаба».
Русские имена на «Маке» после разархивации ZIP
Я вчера скачал несколько десятков

Эта давнишняя проблема «Мака», проистекающая из родовой травмы
Как бы там ни было, в конце индикатора прогресса я увидел кучу файлов с нечитаемыми именами. Ничего готового я быстро не нашёл, поэтому сварганил небольшой скрипт на «баше», который восстанавливает русские имена разархивированного
Способ употребления такой: складываете всё испорченное