/book

Primary LanguageDockerfile

  1. install docker
  2. install vscode
  3. open several terminals

Введение

Главная моя идея продемонстрировать похожесть языков друг на друга и то, что технология развивается эволюционно и современные технологии, до сих пор несут на себе отпечаток решений принятых десятилетия, если не столетия, назад.

Шутка про задницу коня и шаттл

Языки

Языки делятся на высокоуровневые и низкоуровневые, современные и старые.

График языков

К сожалению, в новых языках сильно ограничена возможность работы с низкоуровневым/опасным? кодом который требует квалификации и понимания принципов работы процессора и памяти.

Высокоуровневые языки скрывают эти механизмы за слоями абстракций и поэтому работа может казаться магией. Я намеренно добавил с++ чтобы продемонстрировать низкоуровневую работу, которая недоступна многим языкам и то как происходит переход к высокоуровневым абстракциям.

Вывод текста

Ресурсы процесса

Для начала нам необходимо понять окружение работающей программы.

В первом приближении при запусуке любой программы создается три потока данные: стандартный поток ввода, стандартный поток вывода, стандартный поток ошибок. В программу можно передать аргументы, а после завершения работы программа вернет код ошибки: 0 если завершилась штатно или любое другое значение в диапазоне 1-255 если возникла какая-то ошибка. Работающей программе можно послать числовой сигнал от 0 до 64 и программа может прерваться и отреагировать на него, впрочем не на все сигналы https://man7.org/linux/man-pages/man7/signal.7.html. Не все программы используют все из перечисленного. Эта философия пришла из UNIX систем, где каждая команда задумывалась как кирпичики лего, которые можно комбинировать друг с другом. Естественно, не все кирпичики подходили друг к другу, но в простейших случаях, когда поток был текстовым комбинировать можно было достаточно произвольно.

Терминал

Картинка телетайпа Раньше компьютеры были в виде мейнфреймов – больших залов заставленных стойками с оборудованием, а подключались к ним с телетайпов: печатных машинок совмещенных с принтерами. Сотрудник печатал команду, она передавалась по линиям связи, мейнфрейм выполнял команду и передавал ответ, который печатался на принтере. Затем принтер заменился на экран, появились персональные компьютеры, а концепция терминала, куда печатаешь команду и получаешь ответ так и работает спустя 50 лет.

Это называется REPL (Read Eval Print Loop): подобие диалога, где вы печатаете команду, подтверждаете её выполнение кнопкой Enter. Команда выполняется. Печатается результат выполнения команды. И терминал предлагает ввести следующую команду.

Выполняемые команды называются CLI (Command Line Interface), в отличие от GUI (Graphical User Interface) где человек взаимодейтвует при помощи мыши, нажимая на различные графические элементы.

bash

Вы видите строку приглашение

root@850958de4b2e:~# 

Это означает что ползователь root, находится на машине под названием 850958de4b2e, в данный момент находится в каталоге ~ (домашний каталог пользователя) и является привилегированным пользователем #.

Чтобы выйти из терминала напечатайте команду и нажмите enter:

exit

Также выйти можно нажав сочетание клавиш Ctrl+D.

echo

Начнем с простой команды, которая получает параметры и просто выводит их в стандартный поток вывода и нажмите enter чтобы подтвердить ввод:

echo привет мир

После каждой команды результат выполнения записывается в переменную $?. Вывести её значение можно при помощи команды echo:

echo $?

Результат будет 0, потому что команда завершилась успешно. Обратите внимание, в этой переменной находится результат выполнения последней команды и выполнив echo мы заменили результат выполнения команды echo привер мир на результат выполнения команды echo $?.

Строка

По-умолчанию параметры разделяются пробелом. Обратите внимание что несколько пробелов подряд схлопывается при выводе

echo 1     2

Что если для нас эти пробелы важны и мы хотим их вывести, для этого нужно взять строку в одинарные кавычки:

echo '1     2'

Обратите внимание что '1 2' воспринимается как один параметр. Мы можем передать еще параметры

echo '1     2'     3     4

С точки зрения команды echo она получила 3 параметра.

Мы можем передать многострочный текст, bash поймет что команда не закончена и не будет выполнять команду пока вы не закроетк кавычку:

echo '1
> 2
> 3
> 4'

Обратите внимание как строка приглашения сменилась на > – это означает что команда не завершена.

Если вы ошиблись и хотите отменить ввод команды нажмите Ctrl+C. Также это стандартное сочетание клавиш которое может прервать большинство выполняющихся команд.

Пайпы

Мы говорили что команды могут собираться в цепочки, когда вывод одной команды передается на вход другой команды:

Вместо того чтобы писать

root@850958de4b2e:~# echo '1
> 2
> 3
> 4'

Есть стандартная команда которая выводит последовательность чисел:

seq 10

Допустим мы хотим получить строки с 3 по 5. Для этого есть две команды: head -n X, где X – число строк которые мы хотим получить с начала стандартного ввода. И tail -n Y где Y – число строк которые мы хотим получить с конца потока, отбросив все строки кроме последних Y.

Здесь строка, имеется ввиду набор символов оканчивающийся переводом строки (аналог клавиши Enter). Также обратите внимание что -n и X с точки зрения командной строки это два параметра, и это ответственность команды интерпретировать эти аргументы так что -n это параметр, а X его значение.

Команды соединяются между собой при помощи символа | (pipe, пайп, труба).

выполните сначала

seq 10 | head -n 5

потом

seq 10 | head -n 5 | tail -n 3

Справка

Большинство команд понимают параметр -h или --help. И выводят справку. Попробуйте вызвать справку по параметрам команды tail:

tail -h

Вы увидите сообщение говорящее что параметр -h неизвестен, для получения справки используйте команду --help.

head: invalid option -- 'h'
Try 'head --help' for more information.

Кстати, поскольку команда завершилась с ошибкой, то в переменной хранящей результат последней команды будет значение 1. Напоминаю, что 0 это успешный результат, а все остальные – считаются ошибочными.

echo $?

Выведите справку по команде tail:

tail --help

Обратите внимание, что большинство параметров содержат короткие односимвольные версии вида -n X и длинные версии --lines=X. Длинные версии удобно использовать в скриптах, поскольку многие команды содержат огромное количество параметров и односимвольные версии очень тяжело запомнить.

Для интереса выведите справку по команде grep которая содержит почти 50 параметров, которые можно комбинировать в любом порядке.

Перепишите команду seq 10 | head -n 5 | tail -n 3 с длинными версиями параметров и убедитесь что результат совпадает с предыдущим.

В данный момент на кране много текста, чтобы очистить его можно нажать сочетание Ctrl+L или выполнить команду

clear

Файлы

ls, cat, pipe to file, file to pipe.

REPL

Откроем 5 терминалов и вызовем команды

docker run -it nix python
docker run -it nix irb
docker run -it nix cling
docker run -it nix ki
docker run -it nix node

Вывод текста

ki: print("123")

python: print("123")

irb: print("123")

cling:

    #include <cstdio>
    printf("123")

node: console.log("123")

print – это функция которая печатает в стандартный поток вывода строку.

строка это массив символов

почти во всех языках строка записывается в виде литерала (не исполняемого кода, которые передаются как есть) заключенного в двойные или одинарные кавычки. Интерпретируемые языки такие как python, ruby, js поддерживают оба вида литералов.

питон добавляет перевод строки

язык состоит из синтаксиса - очень маленького набора правил и стандартной библиотеки.

библиотека – это логически и физически сгруппированный набор кода (классов, методов, функций, процедур) для того чтобы избегать замусоривания и дубликатов. Также используется для ускорения кода: подключается только то что необходимо. Почти всегда логическое отображение задается расположением кода в папках и подпапках.

функция аналогична математической: получает что-то на вход и возвращает результат. Функция может ничего не возвращать, как например принт, в бейсике такое называлось процедурой. В современных языка процедур нет, а вместо них функции которые возвращают специальное пустое значение void или nil.

Модули могут содержать подмодули и обычно разделяются точками. Но могут разделяться через / в с/с++ или :: в руби

Можно видеть что в с функция печати не доступна по-умолчанию и приходится её подключать. При этом в js функции печати нет, но есть модуль console и метод log.

Документация

По всем функциям есть документация

функция print в модуле kotlin.io https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/print.html функция print в модуле IO https://www.rubydoc.info/stdlib/core/IO:print функция print без модуля https://docs.python.org/3/library/functions.html#print функция printf из модуля cstdio https://en.cppreference.com/w/cpp/io/c/printf

Выход

Выход из компилятора обычно при помощи ctrl+d. Либо в ki можно послать команду repl :q в python quit() в руби quit в clang .q в js process.exit()

Кодировка

Продолжаем работу со строками и рассмотрим перевод строки. Раньше каждый символ кодировался одним байтом и было всего 2^8=256 значений. Очевидно их не хватало и поэтому существовали кодировки где первые 128 символов были одинаковые а вторые 128 были специфичны для каждого языка. Самые распростаненные кодировки это latin-1 или win-1251 с кириллицей. Если кодировка была неправильная то мы видели кракозябры вместо текста.

таблица символов

В таблице символов, есть непечатаемые или управляющие символы. Один из них это LF, Line Feed, 0A, 10 который "прокручивает бумагу" на одну строку вверх и CR, Carriage return, 0D, 13 который переводит "печатающую головку" влево. https://en.wikipedia.org/wiki/Newline. Эти символы пришли к нам из эпохи Морзе 1870-го года. В разных системах они используются по-разному: в Windows перевод строки в текстовом файле обозначается СR LF, в Linux системах достаточно только LF. Поэтому если мы откроем текстовый файл созданный в Linux в Блокноте на Windows мы увидем как все строки слиплись в одну – это из-за того, что блокнот переносит строку только если встретт оба символа.

#TODO https://refspecs.linuxfoundation.org/fhs.shtml