Как инженеры мы знаем, что компьютеры отлично справляются с вычислительными
задачами. У нас есть широкий спектр инструментов, которые позволяют нам быть
более продуктивными и решать более сложные
задачи при работе над любыми проблемами, которые так или иначе что-то выполняют.
Однако многие из нас используют лишь малую часть этих инструментов: мы знаем
достаточно магических заклинаний только наизусть, и слепо копируем
команды из stackoverflow, когда мы не знаем, как что-то сделать с системой.
Примерами таких систем является apt
, vim
, git
, docker
и такой список
можно достаточно длинно продолжать.
Этот курс мы решили провести, чтобы закрыть проблему непонимания таких популярных технологий и рассказать, что стоит за многими инструментами/фреймворками, а также повысить Вашу продуктивность, чтобы Вы лучше понимали, как работают Ваши повседневные вещи. Я, лектор, решил взять на себя смелость рассказать достаточно большой и сложный багаж знаний, который я накапливал долгое время (в том числе и со stackoverflow, друзей, индустрии) и который, кажется, не был рассказан ни на одном курсе Факультета Компьютерных Наук. Я не утверждаю, что я знаю всё, я до сих пор учусь и повышаю свою инженерную продуктивность — этот процесс достаточно долгий и постоянно развивающийся, к тому же у каждого свой идеальный набор инструментов.
У меня нет задачи заставить Вас использовать что-то, что я использую. Я хочу показать различные варианты, рассказать интересные идеи, стоящие за ними, и показать, как знаю всё, я до сих пор учусь и повышаю свою инженерную продуктивность — этот процесс достаточно долгий и постоянно развивающийся, к тому же у каждого свой идеальный набор инструментов.
У меня нет задачи заставить Вас использовать что-то, что я использую. Я хочу показать различные варианты, рассказать интересные идеи, стоящие за ними, и показать, как оно работает изнутри, чтобы оно перестало казаться "магией".
Будет 13 лекций, каждая из которых затронет какую-то тему. Темы по большей части не связаны между собой, но каждая так или иначе всплывает в работе инженера на системах Linux и MacOS (извините, Windows почти не затронем), чтении и написании статьей или документации, при запуске сервисов, виртуализации, open-source культуры, тестирования, сборки и воспроизведении результатов других. Последняя лекция будет посвящена темам, которые интересны Вам, если Вы хотите, чтобы я покрыл какие-то темы на последней лекции, заполните форму, она будет полностью в записи и без конспектов.
Будет 4 домашних задания. Например, идеи, которые на начало курса есть у лектора и которые скорее всего воплотятся:
- Shell scripting
- git practice
- gdb coredumps debug
- Опубликовать своё резюме в LaTeX через github actions
Финальная оценка будет ставиться как среднее всех домашних заданий и только из них, экзамена не будет, семинаров тоже, обязательного посещения тоже нет. Домашние задания не округляются и берутся дробные оценки в зависимости от критериев. Лекции будут записываться и выкладываться. Единственные преимущества быть на лекции — возможность задавать вопросы лично и получать быстрые ответы. Текстовые лекции не будут такими захватывающими, потому что в этом курсе много надо показывать, что тоже может являться мотивацией быть на онлайн-лекциях. Также если несколько людей найдут достаточное количество опечаток в конспектах или хорошие замечания, могут рассчитывать на бонусы, размер бонуса будет абсолютно субъективным на усмотрение лектора.
Также подписывайтесь на телеграм канал, я там буду делать объявления. Он является основной и полной точкой получения информации. Чата не будет, если есть вопросы, пишите напрямую мне в Telegram.
У компьютеров сейчас уже очень много интерфейсов работы, будь то полностью графический, как в Windows, будь то уже голосовой, как у ассистентов. Но они достаточно ограничены в своих действиях — мы пока не умеем голосом объяснять любые команды или UX может быть ограниченным. Исторически так сложилось (и по существу), что текстовые интерфейсы самые гибкие и намного проще для реализации. Откуда появился старый добрый Shell.
Все платформы, которые Вы используете, имеют тот или иной shell. Сегодня мы
поговорим о самом популярном shell — Bourne Again SHell, или "bash" как его
ещё называют. Чтобы открыть терминал, который запустит Вам bash на Ubuntu,
надо ввести shortcut Ctrl + Alt + T
, на MacOS нет дефолтного шортката, поэтому
надо через поиск или графический интерфейс. Если у Вас что-то другое, Вы уже
сами знаете, как открывать терминал.
Когда Вы открываете терминал с bash, у Вас перед глазами будет что-то похожее на следующее:
danlark@danlark:~$
Это основной текстовый интерфейс. Он показывает Вам, кто Вы, на какой машине, и
где Вы находитесь. Первый danlark
— это кто я, второй danlark
—
машина на которой я нахожусь. ~
— стандартное обозначение home
директории
в Вашей системе, $
обозначает, что Вы не root пользователь.
Дальше shell предоставляет Вам исполнять команды
danlark@danlark:~$ whoami
danlark
danlark@danlark:~$ hostname
danlark
Как они исполняются? Как и в языках программирования, в Shell есть глобальные
переменные, которые Вас окружают. В bash одна из основных глобальных переменных —
это $PATH
. Ещё такие переменные называются переменными окружения. Чтобы их
вывести, надо обязательно перед ними поставить знак $
, а команда echo
умеет
выводить аргументы командной строки, причём echo
ничего не знает про
$PATH
— сам bash раскрывает эту переменную при исполнении.
danlark@danlark:~$ echo PATH
PATH
danlark@danlark:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Теперь, когда Вы пишите любую команду, shell поочередно смотрит на все пути,
указанные в $PATH
, и исполняет эту команду. Конфликты решаются по первому
попавшемуся пути в переменной. Например, у меня бинарный файл whoami
на самом
деле лежит по /usr/bin/whoami
. Вы можете это узнать, написав команду which
.
danlark@danlark:~$ which whoami
/usr/bin/whoami
danlark@danlark:~$ which which
/usr/bin/which
Вы также можете переопределять эти переменные перед командами, например:
danlark@danlark:~$ PATH=/usr/local/bin whoami
bash: whoami: command not found
danlark@danlark:~$ PATH=/usr/bin whoami
danlark
С аргументами в shell есть сложности: основной разделитель является пробелом,
а иногда аргументы хочется иметь с пробелами. Для этого используют так
называемую технику escaping через обратный слеш \
, а также кавычки.
Например, при навигации по директориям, если какая-то названа hse course
, то
её создавать или в неё входить можно так:
danlark@danlark:~$ mkdir hse\ course
danlark@danlark:~$ cd "hse course"
danlark@danlark:~/hse course$ pwd
/home/danlark/hse course
danlark@danlark:~/hse course$
Кавычки можно брать как и одинарные, так и двойные. И если Вам хочется какую-то кавычку использовать в названии, то её можно окружить кавычками другого типа и всё будет работать:
danlark@danlark:~$ mkdir 'hse\ "course'
danlark@danlark:~$ cd 'hse\ "course'
danlark@danlark:~/hse\ "course$
Кстати, про навигацию внутри файловой системы. В Linux системах всё находится
под одной точкой, называемой "root" или /
. Все остальные файлы, девайсы
находятся под /
. Основные команды для навигации:
danlark@danlark:~$ pwd
/home/danlark
danlark@danlark:~$ cd /home
danlark@danlark:/home$ pwd
/home
danlark@danlark:/home$ cd ..
danlark@danlark:/$ pwd
/
danlark@danlark:/$ cd ./home
danlark@danlark:/home$ pwd
/home
danlark@danlark:/home$ cd danlark
danlark@danlark:~$ pwd
/home/danlark
danlark@danlark:~$ ../../bin/echo hello
hello
Путь, начинающийся с /
— абсолютный путь, иначе он относительный. .
— это
текущая директория, ..
— родительская директория (предыдущая до последнего
/
), pwd
— это команда print working directory.
Стоит отметить, что команда cd -
вернёт Вас на предыдущую директорию, в
которой Вы были. Бывает полезно, когда Вы прыгаете между двумя директориями. А
cd ~
вернёт Вас в Вашу home директорию.
Почти все команды работают с текущей директорией. Например, чтобы посмотреть,
что за файлы и папки находятся в текущей директории, достаточно запустить
команду ls
— list.
danlark@danlark:~$ ls
- Documents
1_5zVzH8TuK1M-oxVnVEY1GA.png Downloads
2020-07-29-155724_1113x656_scrot.png First
2020-07-29-163555_1585x422_scrot.png format-benchmark
...
У команд как правило есть аргументы (или опции), это то, что вы пишете после команды. Аргументы неформально делятся на два типа
- Позиционные. Например,
$ cd /etc
, вы передаёте командеcd
аргумент, что надо пойти в директорию/etc
. - Опциональные. Это аргументы обычно начинаются с
-
или--
(как их разделить не знаю, почти везде работает просто-
). Пример:$ ls -l
(см. ниже)
Аргументы позиционные и опциональные могут совмещаться
$ ls -d /etc
$ ls -dl /etc
, пример, что однобуквенные аргументы в некоторых командах можно склеивать$ ls --author -l .
, пример, когда можно совмещать много различных других аргументов
Сложно, конечно, запомнить аргументы, и они очень несистематичны. Я лично пользуюсь
tldr, который показывает наиболее популярные использования
той или иной команды, если я что-то не помню. Особенно полезно для каких-нибудь
find
и tar
. Например, на картинке ниже показана динамика количества
аргументов у популярных bash команд за время их
развития:
Чтобы посмотреть больше информации, у ls
есть опция -l
, вывод будет
более полным:
danlark@danlark:~$ ls -l
total 250928
drwxr-xr-x 1 danlark primarygroup 224044 May 4 13:11 dir_name
-rw-r----- 1 danlark primarygroup 110021 Jul 29 15:45 1_5zVzH8TuK1M-oxVnVEY1GA.png
-rw-r----- 1 danlark primarygroup 144485 Jul 29 15:57 2020-07-29-155724_1113x656_scrot.png
-rw-r----- 1 danlark primarygroup 92167 Jul 29 16:35 2020-07-29-163555_1585x422_scrot.png
-rw-r----- 1 danlark primarygroup 92031 Jul 29 16:36 2020-07-29-163646_1585x418_scrot.png
На некоторых современных bash ls -l
можно просто заменить на ll
.
drwxr-xr-x 1 danlark primarygroup 224044 May 4 13:11 dir_name
Разберём, что оно выводит. d
бит показывает, что это директория, первый rwx
показывает, что директория может читаться, перезаписываться и входиться от
пользователя danlark
. Вторые r-x
показывают, что группа primarygroup
может читать и заходить, третьи показывают r-x
, что все остальные помимо
owner и owner group могут читать и заходить. Стоит отметить, что бит x
это execute, для файлов это означает, что файл может исполняться (например, скомпилированный бинарный файл или скрипт), а для директорий это возможность в неё входить. Единица после доступов показывает
количество hard link на директорию, но это выходит за рамки нашей лекции.
Так как битов по 3, то их представляют в 8-ричной системе счисления и эти
доступы можно менять, например:
danlark@danlark:~$ chmod 775 dir_name
danlark@danlark:~$ ls -ld dir_name
drwxrwxr-x 2 danlark primarygroup 4096 Aug 16 15:55 dir_name
Остальные интересные команды для работы с директориями — это mv $src $dst
(move), cp $src $dst
(copy), mkdir $dir
(make directory), rm $file
(remove),
rmdir $dir
(remove empty directory), rm -r $dir
(remove recursive),
touch $file
(touch a file, то есть создание файла).
Если Вы хоть когда-то хотите что-то большее узнать про какую-либо команду, её
опции и прочее, всегда можно ввести man $cmd
или cmd --help
, которые должны
помочь или tldr
(см. выше).
В man
навигация идёт обычными стрелками, но если Вы хотите что-то поискать,
то shortcuts следующие:
- / search string — ищёт “search string” в текущем man
- n — к следующему совпадению строки
- shift + n — предыдущее совпадение строки
Вы скорее всего уже часто сталкивались с тем, что Вам приходится писать sudo
в командах, в частности при установке пакетов. sudo
обозначает "super user do" и
нужно, когда Вам нужны доступы к папкам/файлам, которые защищены от всех
остальных пользователей. В общем случае sudo
позволяет привилегированным
пользователям исполнять команды из-под любого другого пользователя.
Например, при установке пакетов в /usr/bin
вы должны быть привилегированным.
Это создано для безопасности, поэтому будьте осторожны всегда, когда Вас просят
что-то сделать с sudo привилегиями, например, не запускайте сторонние бинарные
файлы с этим доступом. Пароль от sudo
по умолчанию хранится 15 минут, то есть
Вам не надо будет вводить новый пароль при повторном использовании sudo
. Если
же Вы хотите всегда быть в root в каких-то операциях, Вы можете войти в su
(super user) мод.
danlark@danlark:~$ sudo su
[sudo] password for danlark:
root@danlark:/home/danlark#
Запускать программы по одной очень хорошо, но иногда хотелось бы вывести вывод программы в файл или на вход другой программы. Для этого в shell есть множество способов, основанные на так называемых потоках или файловых дескрипторах.
Самые простые формы перенаправления — <file
и >file
. Первое
обозначает, что вход программы должен браться из file
, а последнее означает,
что file
должен перезаписаться выводом программы. >>file
означает, что в
file
будет добавлен вывод программы. Рассмотрим простейшие примеры (cat
,
кстати, команда для прочтения файла или stdin, если запущена без аргументов):
danlark@danlark:~$ echo hello >hello.txt
danlark@danlark:~$ cat hello.txt
hello
danlark@danlark:~$ cat <hello.txt # нет аргументов, просто запуск из stdin hello.txt
hello
danlark@danlark:~$ cat <hello.txt >hello2.txt
danlark@danlark:~$ cat hello2.txt
hello
danlark@danlark:~$ echo " world" >>hello2.txt
danlark@danlark:~$ cat hello2.txt
hello world
Также выход одной программы можно перенаправлять на вход другой через оператор
pipe |
, например:
danlark@danlark:~$ ls -l | head -n 3
total 250712
-rw-r----- 1 danlark primarygroup 110021 Jul 29 15:45 1_5zVzH8TuK1M-oxVnVEY1GA.png
-rw-r----- 1 danlark primarygroup 144485 Jul 29 15:57 2020-07-29-155724_1113x656_scrot.png
Или что-то более сложное:
danlark@danlark~$ curl --head -s google.com | grep -i content-length | cut --delimiter=' ' -f2
219
Последняя команда взяла header сайта google.com, поискала с помощью grep
слово
content-length
в любом регистре и вывела 2-й токен с разделителем пробел.
Помните, что иногда в файлы нельзя ничего записать:
danlark@danlark:~$ touch hello.txt
danlark@danlark:~$ chmod 000 hello.txt
danlark@danlark:~$ echo hello >hello.txt
bash: hello.txt: Permission denied
Но для некоторых может стать удивлением, что в hello.txt
нельзя записать с
sudo:
danlark@danlark:~$ sudo echo hello >hello.txt
bash: hello.txt: Permission denied
Так происходит, потому что echo запускается с sudo
, а >hello.txt
это всего
лишь перенаправление, которое контролируется самим bash. Чтобы избежать такого
в будущем, стоит использовать sudo su
, как писалось выше, или окружать
полностью команду в sudo:
danlark@danlark:~$ sudo echo hello >hello.txt
bash: hello.txt: Permission denied
danlark@danlark:~$ sudo bash -c 'echo hello >hello.txt'
danlark@danlark:~$ sudo cat hello.txt
hello
danlark@danlark:~$ sudo cat <hello.txt
bash: hello.txt: Permission denied
Если Вы хотите исключить весь вывод, стандартным способом является
перенаправление stdout >/dev/null
.
Стоит отметить, что существует 2>file
— это перенаправление stderr
в
file
. Если Вы хотите полностью исключить любой вывод в консоль, лучший способ
>/dev/null 2>/dev/null
. А если Вам надо что-то поискать по stderr
, можно
его перенаправить в stdout
с помощью 2>&1 | grep $your_token
:
danlark@danlark:~$ man | grep you
What manual page do you want?
For example, try 'man man'.
danlark@danlark:~$ man 2>&1 | grep you
What manual page do you want?
danlark@danlark:~$ man 2>&1 >/dev/null | grep you
What manual page do you want?
danlark@danlark:~$ man 2>&1 2>/dev/null | grep you
What manual page do you want?
danlark@danlark:~$ man 2>/dev/null | grep you
Вы можете писать множество команд через &&
, где часть справа выполнится только
если часть слева корректно (с кодом возврата 0) завершилась:
danlark@danlark:~$ ls | head -n 5 && echo OK!
1_5zVzH8TuK1M-oxVnVEY1GA.png
2020-07-29-155724_1113x656_scrot.png
2020-07-29-163555_1585x422_scrot.png
2020-07-29-163646_1585x418_scrot.png
2020-07-29-163706_1582x421_scrot.png
OK!
Иногда Вы можете встретить команду &
, она делает detach процесса — это
значит, что процесс принадлежит терминалу (при его закрытии, он умрет), но
shell этот процесс не блокирует, то есть другие команды выполнять можно. Чтобы
быть уверенным, что Ваша команда выполнится в фоне, даже если закрыть терминал,
можно использовать tmux (будет в конце лекции), либо использовать команду
nohup
:
danlark@danlark:~$ nohup ./server --port=1488 &
Всё, сервер работает и будет работать даже если закроете терминал.
Если Вам не нравится печатать долго какую-то команду, то в bash можно
выстраивать алиасы. А именно в Вашей home dir должен быть файл .bashrc
,
в котором можно в конце писать алиасы, которыми можно дальше пользоваться в bash:
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
alias lah='ls -lah'
alias lmao='touch all'
Когда Вы ходите по директориям или работаете в git, могут предоставляться так
называемые tab-completions. Например, если я хочу пойти в какую-то директорию с
префиксом Do
, я пишу cd Do
и жму TAB 1 или 2 раза и появляются варианты:
danlark@danlark:~$ cd Do
Documents/ Downloads/
И Вы можете видеть весь список предложенных. В итоге достаточно хорошим правилом является жать TAB примерно всегда, чтобы быстрее перемещаться по директориям или чтобы автодополнялись команды. К сожалению, в bash не самая лучшая поддержка tab-completion.
Bash, к сожалению, достаточно ограничен в своём функционале. Существуют множество расширений shell, одни из самых примечательных — это oh my zsh и fish. Последний не совсем совместим с bash, поэтому для начала я рекомендую использовать просто oh my zsh.
Он лучше умеет дополнять по tab, умеет предлагать выборы при повторном нажатии tab. Одна из отличительных способностей этих shell — возможность искать по истории Ваших команд, когда в bash Вы только можете взять предыдущие команды, нажимая на стрелку вверх, например:
➜ ~ mv Down
# Нажимаю стрелку вверх
➜ ~ mv Downloads/big_max_cost_flow.in .
И команда, которую я делал недавно, вывелась.
fish делает это умнее: выдаёт предложения исходя из частоты использования и т.д.
Мой совет — откажитесь от обычного bash и используйте zsh или fish. Чтобы
их запускать при открытии терминала, существует один всегда работающий способ:
в конце .bashrc
добавить команду exec zsh
или exec fish
. В интернете полно
туториалов по кастомизации этих терминалов, возьмите тот, который Вам нравится
больше всего. У меня нет задачи заставить Вас пользоваться тем, чем я пользуюсь.
Пример установки и кастомизации zsh от TmLev.
tmux — отдельная утилита для шелла, которая рассчитана на мультиработу и хранение состояний терминалов. Например, каждый раз Вам надо открывать новый терминал, чтобы сделать что-то интересное, как ни странно, если Вы делаете какую-то долгую работу и отправляете машину в спящий режим, случайно закрываете терминал или сеть обрывается с сервером, то процесс остановится. tmux создан для решений этих проблем, он работает в фоне всегда путём сохранения state Ваших терминальных окон.
В tmux можно создавать сессии, в которых Вы работаете, сессии состоят из окон — это наборы терминалов, а окна из панелей — это отдельные обычные терминалы. Вот некоторые шорткаты, как работать с панелями:
Ctrl+b "
— создать новую панель горизонтально от выбраннойCtrl+b %
— создать новую панель вертикально от выбраннойCtrl+b arrow key
— смена панелиCtrl+b c
— создание нового окнаCtrl+b n
— переключение на следующее окноCtrl+b p
— переключение на предыдудщее окноCtrl+b w
— показ всех сессий и окон и интерфейс для переключенияCtrl+b ?
— показ всех командCtrl+d, exit
— выход из панели, возвращение на предыдущую панель
Более подробный список команд можно найти здесь и здесь.
cd
,mkdir
,touch
,rm
,pwd
,ls
— см. вышеsort
,uniq
— сортировка и вывод уникальных (вход должен быть отсортированным)grep
,cut
— поиск по регулярному выражению (см. след лекцию) и сплит строкhead
,tail
— вывод первых и последних строкwc
— подсчёт количества байт, строк в файле и т.д.df
— статистика использованного места на машинеcat
,tac
— вывод файла с начала или с конца соответственноecho
— повторение аргументовfind
— мощная команда для поиска в директорииchmod
,chown
,sudo
— изменение permissions и овнеров, работа в режиме super user- Используйте перенаправления
>, <, 2>, >>, 2>>, 2>&1, |
. Вспомните, что каждое означает