- Содержание
- Начнём, пожалуй
- Чуть поговорим о файловой системе в Linux
- Основные команды работы с файлами
- Скрипты shell
- Переменные окружения
- Команды для обработки вывода
- Чему научились?
- Ресурсы
Привет! В этой теме пройдёмся по основным моментам, которые нужно знать, чтобы безболезненно пользоваться командной оболочкой Shell (Bourne Shell).
Вообще, в Ubuntu оболочка по-умолчанию - Bash (Bourne again shell). Существует и куча других оболочек, например, zsh, fish, xsh и другие. Главная суть в том, что все они реализуют набор команд, с помощью которых можно управлять операционной системой.
Важно, POSIX-совместимых команд - это стандарт такой =)
На самом деле, когда в файловом менеджере мы перетаскиваем мышкой папку или файлы, удаляем что-то, делаем какие-то действия с помощью графического интерфейса (GUI - Graphical User Interface), под капотом (внутри системы) исполняются те или иные команды CLI (Command Line Interface).
Не всегда напрямую те, что мы разберём, но логика такова, что вся графика - это надстройка над рядом базовых действий, которые можно сделать командами в Shell.
Поэтому, сегодня наша цель - разобраться как работать с командной строкой!
Поехали, открываем терминал (находим в меню приложений Terminal) и видим это:
У тебя может быть другое название зелёными буквами и название терминала =)
Это и есть терминал, в котором мы будем вводить наши команды. Давайте начнём наше знакомство с первой команды:
pwd
pwd- команда вывода директории, в которой находимся сейчас
В результате увидите /home/user вывод.
Отлично! Простая первая команда удалась, но мы отклонились от традиций, обычно же знакомство начинается с "Hello World!", не будем упускать возможность и познакомимся с командой вывода echo:
echo "Hello World!"Ю-ху! Наш первый Hello-World! Поздравляю!
Давай подробнее рассмотрим, почему путь выглядит именно так и что это за символы '/'?
Вся файловая система в Linux устроена в виде дерева. Вот, взгляните:
Подробнее про каждую директорию кратко расписано здесь
По сути, путь в виде строки '/' - это путь до корня файловой системе. В корне лежат все остальные папки, а в них лежат другие подпапки.
Так как нам интерпретировать путь /home/user? В корне лежит директория home, внутри которой есть директория user, внутри которой мы и находимся.
На самом деле в Windows используются такие же пути, но там вместо корня диски (C:\\, D:\\ и т.д.), а папки разделяет символ \.
Теперь, когда мы знаем, как вывести директорию, в которой мы находимся и понимаем, как устроены папки и файлы в Linux, пора научиться ими управлять!
Самая первая команда, которой стоит научиться - это команда вывода файлов и директорий в конкретной папке. Для этого используем ls:
ls
# Вывод: Downloads Pictures и т.д.В зависимости от языка названия папок могут меняться в системе.
Отлично, но что, если мне хочется больше информации о папках и директориях? Вот тут мы встречаемся с опциями команд! Опции - это расширения команд, которые позволяют задать желаемое поведение (изменить под себя). Ведь удобно вывести просто список директорий и папок, но что если нужно больше информации? Используем опцию -l!
ls -lи видим
total 40
drwxr-xr-x 15 user user 4096 Aug 6 23:56 Downloads
...Вооу, сколько информации. Тут и дата последнего редактирования, и пользователь, владеющий файлами и папками и много другого, но мы пока сконцентрируемся на том, что это крутая опция!
У большинства команд есть опция
-h(или длинная опция--help), которая выводит информацию по всем возможным настройкам утилиты.
💪 Выведи помощь к команде ls и прочитай, какие ещё есть опции у неё.
Хорошо, выводить информацию полезно, но ещё полезнее научиться управлять файлами и папками. Следующая команда mkdir ("make directory") - позволит создавать директории.
💪 Создай папку, введя mkdir super_dir или другое имя вместо "super_dir" в качестве аргумента команды. Проверь в ls и файловом менеджере, что папка создана.
Аргумент - дополнительная информация, которая передаётся после команды. Опция отличается наличием символа "-".
Вы смогли сами создать папку? Крууутооо! Погнали внутрь!
Так, мы папку создали и даже смогли зайти в неё в файловом менеджере, но как нам передвигаться в терминале? Всё просто! Для этого есть команда cd ("change directory").
💪 Перейди в директорию командой cd super_dir. Выведи с помощью pwd нынешний путь и проверь, что переход удачен.
💪 А теперь вопрос на подумать, почему, после первого выполнения перехода в "super_dir" второй уже не работает? А если открыть терминал заново, то снова, один раз работает, а другой раз нет?
Так, мы освоили способ перемещения, но ведь всё подкрепляется практикой, пора создать целую структуру.
💪 Создай следующую структуру папок и проверь себя в файловом менеджере. Убедитесь, что вы можете перемещаться по всем этим директориям без проблем.
- super_dir
- fruits
- apple
- orange
- pear
- vegetables
- lettuce
- onion
- cucumber
- spinach
- fruits
Обратим внимание, что два раза команду не выполнить, так как при переходе в папку "super_dir" мы уже находимся в ней. То есть, команда cd super_dir - это переход в директорию из нынешней директории. Если внутри super_dir нет второй с тем же именем, то и команда несколько раз работать не будет.
Думаю понятно, что как в случае mkdir, так и в случае cd требуется аргумент, которым является имя для создания/перехода. Этим аргументом у нас являлась директория "super_dir" - работа с директорией из нынешней папки.
Так мы познакомились с относительным путем.
Относительный (Relative) путь - путь в файловой системе от нынешнего положения. Может быть
super_dirили./super_dir. "." - это символ, который при использовании в пути можно заменить на "отсюда" ("current directory").
Короче, если хотим создавать и делать что-то из нынешней директории, то пользуемся относительными путями.
А что если теперь выполнить команду cd /home/user/super_dir (обрати внимание, у тебя вместо user в pwd могло быть другое имя пользователя)? Попробуй! Несколько раз подряд? 💪
Интересно, а такая команда выполняется, почему?
Всё просто, в этом случае мы задаём абсолютный путь в файловой системе:
Абсолютный (Absolute) путь - путь в файловой системе от "
/" (корня).
Абсолютным путёём не всегда удобно пользоваться, но в некоторых ситуациях он полезен, поэтому мотаем на ус.
Если так подумать, то после создания нашей базы знаний фруктов и овощей (задачка про папки с fruits/vegetables) мы умеем только двигаться вперёд с помощью cd и относительного пути.
После изучения абсолютного пути, мы может вернуться в корень нашей базы (cd /home/user/super_dir) и снова двигаться вглубь. Но что если я хочу из папки orange вернуться в папку fruits?
Да можно сделать
cd /home/user/super_dir/fruits, но смотри дальше, там будет фокус с точками!
Что, если я скажу, что "." - это нынешняя директория (можешь даже попробовать cd . =)), а директория выше по дереву - это, погоди-погоди, две точки!
Да, именно ".." определяет путь до папки выше по дереву. (В некоторых интерпретаторах "..." - это подъём на два уровня выше).
Итого, если тебе нужно передвинуться из apple папки в папку fruits - просто делаешь cd .. и вот, цель достигнута!
💪 Ну всё, теперь ты умеешь просто профессионально двигаться в командной строке! Погнали, зайди в каждую папку, выйди из неё и переместись в следующую! Время путешествий!
Так, мы подошли к моменту, когда в нашей базе мы не хотим иметь лук (onion), не нравится он нам, а поменяем его на тыкву!
Синтаксис команды для переименования папок и файлов:
mv <оригинальное имя> <новое имя>Например, mv super_dir new_super_dir переименует нашу базовую директорию. Делать это не обязательно, пойдём сразу практиковаться!
💪 Переименуй лук в тыкву (pumpkin). Также, переименуй один любой фрукт в любой другой фрукт.
Такс, такс, базу мы подредактировали, молодцы!
Папки это хорошо, но мы не за тем учимся терминалу, чтобы просто создавать папки! Сейчас мы очень быстро научимся создавать и редактировать текстовые файлы!
А с учётом того, что исходники - это текстовые файлы, то это очень полезный навык!
Переходим в директорию super_dir (это вы уже умеете, так что сами) и создаём там текстовый файл с описанием нашей базы фруктов и овощей:
nano description.txtОткроется редактор нового файла:
Работать в нём просто, двигаете курсор с помощью стрелок указателей и набираете текст.
Чтобы выйти, нам помогает подсказка "^X Exit". Символ "^" означает клавишу "Ctrl", так что для выхода нажимаете "Ctrl+X".
Но перед этим надо сохранить файл, "^O Write Out", то есть, "Ctrl+O".
Если не сохранить, но выйти - нам напомнят о том, что файл не сохранен! Удобно!
В nano ещё куча разных hotkey комбинаций, например, вырезать всю строку, поиск в файле и т.д. Больше инфы найдете здесь!
Обычно в практике nano не используется постоянно, но это удобно, если нужно быстро подредактировать/посмотреть какой-то файл, а в редакторе типа VSCode отдельно открывать долго.
Если хотите просто создать пустой файл и не редактировать его, то можно воспользоваться командой
touch another_description.txt(имя файла своё), но на практике такое нужно редко, так чтоnanoрулит.
💪 Самое время в каждой папке фрукта и овоща написать краткое описание с помощью nano. Например, в description.txt внутри "apple" папки пишем "Красное и круглое". Попробуйте создавать и редактировать файлы с помощью относительных и абсолютных путей. Так же, помимо nano есть много других популярных текстовых редакторов, например Vim или Emacs, не бойтесь экспериментировать и выбирать инструменты себе по душе.
Еще один популярный текстовый редактор, менее дружелюбен к пользователю чем nano, но обладает большим количеством плагинов, позволяющих собрать из него почти полноценную IDE. Обычно имеет в комплекте с пакетом самого редактора идет полноценный учебник по использованию - Vimtutor. Там описываются все основные горячие клавиши, лайфхаки по общему принципу использования и т.п. Если сказать коротко то Vim имеет три режима работы
- Командный
- Режим вставки
- Визуальный При открытии файла вы первоначально находитесь в командном режиме
vim file.txt
Чтобы перейти в режим вставки достаточно нажать i, после чего вы сможете печатать. После внесения изменений нажимаем "ESC" для выхода в "командный режим", вводим ":" (двоеточие), вводим "wq" (write-quit) - для сохранения изменений и выхода; "q!" - для выхода без сохранения, и нажимаем "Enter". Горячие клавиши и особенности работы с текстом сможете узнать в Vimtutor, если вам приглянется этот текстовый редактор :)
Стоит упомянуть и о возможности удаления файлов и папок с помощью команды rm.
Чтобы удалить файл, достаточно написать rm description.txt, то есть, просто указав путь до файла в качесте аргумента.
Для удаления папок используем опцию -r, которая проходит внутрь папок и удаляет файлы и папки внутри (рекурсивно).
Смотри, мы сделали уже кучу действий и каждую команду набирали вручную. А что, если нам потребуется выполнить эти действия на другом компьютере повторно? Например, снова создать структуру файлов, которую мы делали ранее.
Вспоминать и по памяти (или с листочка) снова их последовательно делать - не вариант! Погнали знакомиться со скриптами!
Скрипты - это просто набор команд, который выполняется последовательно. Есть ещё широкоизвестное название "макросы", но тут им не пользуются.
Чтобы сделать Bash скрипт, достаточно создать файл с расширением .sh.
💪 Перейди в папку "super_dir" и внутри создай файл my_first_script.sh. Внутри скрипта напиши всего одну команду - echo "Hello World!".
Отлично, у нас есть скрипт, который приветствует, но как его вызвать, чтобы он выполнил команды? Всё очень просто, явно вызываем интерпретатор:
bash my_first_script.shВеликолепно! Вот мы и научились создавать скрипты! Но мы на этом не останавливаемся - дальше интереснее!
Внутри bash существует возможность использовать переменные. Определяются они максимально просто, пишем имя переменной, знак "=", значение.
⚠️ Важно, что пробелов между именем, "=" и значением быть не должно!!!
Например, чтобы вывести "World" через переменную, делаем так:
WORLD_STRING="world"
echo "Hello $WORLD_STRING!"Заметили? В первой строке определили переменную, а в третьей к ней обратились. Обращение к переменной делается через символ "$".
Но что, если мне надо вывести прямо символ "$"? В таком случае ведь всё после этого символа будет использовано как имя переменной? Агась, но для этого можно использовать символ экранирования "
\". Напримерecho "Million \$s i have"
💪 В своём скрипте напиши код, который будет выводить строку "Hello World! My name is User!", где вместо "User" будет подставляться твоё имя.
В ряде случаев мы не можем явно указать вызов интерпретатора bash script.sh.
Как быть? Как нам тогда запускать скрипты, ведь это так удобно!
Что если я скажу тебе, что можно прописать интепретатор прямо в файле! Как это сделать? Сейчас покажу, прописывай это в начало своего скрипта самой первой строкой:
#!/usr/bin/bashТакая строка называется shebang и такую штуку можно встретить не только в Bash скриптах. Главное, что это только одна часть исполняемости. Мы пока только прописали интерпретатор, а в Linux нужно сделать ещё один момент, дать файлу права на исполнение.
Shebang имеет синтаксис
#!interpreter [optional-arg].interpreterдолжен быть абсолютным путём до интерпретатора.
chmod +x my_first_script.shКоманда
chmodпозволяет менять "права" у файла, например, можно сделать файл "read-only", или (как в нашем случае) сделать скрипт исполняемым.
После этого выведи ls -l my_first_script.sh и в строке разрешений будет видна буква "x" - это значит, что файл стал исполняемым!
Теперь, после этих незамысловатых магических действий (ещё раз, в файл прописали интерпретатор и сделали файл исполняемым) мы можем вызывать скрипт всего лишь вот так:
./my_first_script.sh
# или по абсолютному пути: /home/user/super_dir/my_first_script.sh, но это обычно неудобно =)В результате мы должны увидеть всё то же самое, что видели при вызове bash my_first_script.sh!
Если получилось - круто! Таким образом, можно сделать любой файл исполняемым, главное прописать, каким интерпретатором исполняемым.
Если прочитаете статью про shebang, то увидите, что лучшей практикой является использовать
#!/usr/bin/env bash.
Помнишь, буквально недавно мы разобрались, что в bash есть переменные. Но те переменные, что есть в скрипте, существуют только при вызове скрипта.
💪 Если сомневаетесь, попробуйте определить переменную MY_SCRIPT_VAR, вызвать скрипт с ней и после вызова проверить, есть ли она в терминале командой echo "$MY_SCRIPT_VAR".
Думаю, ты удивишься, если мы представим, что весь терминал - это один большой долго исполняющийся скрипт =)
Это всё к чему? В нашем терминале определена куча разных переменных, которые используются системой. Чтобы получить этот список, достаточно вызвать команду env. Попробуйте!
Этой командой мы выводим весь список переменных окружения, которые определены в сессии терминала. Воу, целых два новых термина ...
Да, начнём с переменных окружения - это переменные, которые немного отличаются от обычных переменных.
Давай представим, что у нас есть скрипт, который вызывает другой скрипт. Так вот, переменные из первого скрипта не будут доступны во втором, так как это обычные переменные.
А вот если её определить через export VARIABLE=value (прописав export перед переменной), то она станет переменной окружения, станет круче и будет видна всем дочерним скриптам (тем, который создаются из основного нашего скрипта).
А зачем нам сейчас это знать? Да всё просто, весь запуск системы - это запуск кучи скриптов одного в другом. А в системе есть пачка полезных переменных окружения, о которых нам надо знать:
HOME- путь до домашней директории пользователя;PATH- пути до директорий, где искать утилиты для исполнения;PWD- путь до нынешней директории;USER- имя пользователя
💪 Попробуй каждую из переменных вывести с помощью echo.
Итого, переменные окружения определяются где-то в запуске и поэтому, будь они обычными, мы бы до них не добрались. А так, просто знайте, что переменные окружения очень полезны.
Такс, а что с сессиями? Что это такое?
Давай проведём простой эксперимент: открой два терминала, в одном определи переменную окружения export MY_VAR=10 и проверь, что в этом терминале она есть в env и выводится через echo.
Отлично, а теперь сделай env и echo (без её определения!) во втором терминале на эту переменную и найди её.
Её нету? Как? Проверь ещё раз!
Окей, если так и не получилось найти, то ты теперь знаешь, что такое сессии - это отдельные пространства, в которых есть свои переменные.
То есть, если создать два терминала, то создаётся две сессии, которые между собой не делятся переменными и остальным. Скажу больше, вызов скрипта - это отдельная сессия, но если определить переменную окружения в терминале и в этом же терминале вызвать скрипт, то это переменная окружения будет доступна скрипту. Но она не будет доступна, если вызвать тот же скрипт в другом терминале.
Запутал? Не переживай! Просто помни, если переменная не определена, то может неправильно сделана настройка установки переменных. Они наследуются по принципу, если раньше не было определено, то и не будет.
Мы уже убедились, что команды в скрипте - это удобно. Раз, и все команды вызваны. Но что, если я хочу сделать также с переменными окружения? Написать скрипт, который в сессии определит все нужные переменные?
Есть в bash такая возможность, называется "env sourcing".
По сути, мы в скрипте пишем экспорты переменных, которые хотим определить в сессии и хитро вызываем. Давай напишем скрипт env_pack.sh:
#!/usr/bin/env bash
export VAR_ONE="one"
export SUPER_VAR="puper"
export BIBA="boba"Сохраним, делаем исполняемым.
Теперь, попробуй вызвать скрипт и после проверить эти переменные через echo:
./env_pack.sh
echo $VAR_ONE
echo $SUPER_VAR
echo $BIBAХм, все строки пустые? Правильно, потому что при вызове скрипта создалась внутренняя сессия, там создались переменные окружения, но наверх их никто не может поднять!
Тогда, давай сделаем sourcing через следующую команду:
source ./env_pack.shПосле этой команды проверь три наших переменнные.
Они на месте! Но что же произошло? Тут все оч просто, по-умолчанию сессия создаётся на каждый вызов скрипта, но source команда заставляет вызвать скрипт в той же сессии, что мы сейчас находимся (сессия терминала).
Итого, вот так можно определять скрипты, которые хранят в себе настройки переменных и подкидывать пачки переменных прямо в сессии.
Команда
source ./env_pack.shаналогична команде. ./env_pack.sh. Да, точка - это командаsource=)
Теперь ещё больше упростим себе жизнь! Мы всё говорим об автоматизации всяких штук, что сложные структуры папок можно создать одним скриптом, что кучу настроек переменных можно сделать одной командой.
Это уже крутые возможности!
Но что, если есть какие-то команды и переменные, которые надо делать/настраивать при запуске терминала? Согласись, было бы удобно иметь такое место, куда можно прописать команды, которые будут делаться каждое создание терминала?
Есть такой вкуснятины у меня для тебя, называется "rc-файл"!
По сути, каждый раз, когда открывается терминал, он делает source $HOME/.bashrc. То есть мы можем отредактировать .bashrc файл, чтобы настроить его так, как нам нужно!
Давайте сделаем это!
💪 По-умолчанию, в .bashrc уже есть команды, поэтому правильным подходом будет написать в конце файла все команды. Пропиши определение переменных "VAR_ONE", "SUPER_VAR" и "BIBA" из предыдущего раздел в bashrc и создай новый терминал. Убедись, что в терминале переменные определены безо всяких действий сразу с запуска.
Хоть
.bashrcи находится в домашней директории, но его не видно в файловом менеджере и в командеls. Привильно, потому что в Linux файлы/папки, имя которых начинается с точки - скрытые. Для них у ls есть опция-a.
Обрати внимание, что мы подставили
$HOMEв путь при выполнении командыsource. Любые переменные можно так использовать! Для$HOMEв Linux есть сокращение~, то есть абсолютный путь до.bashrcможно сформировать как~/.bashrc.
Вот так, теперь, когда ты умеешь настраивать запуск терминала под себя, тебе любая проблема по плечу!
Последнее, о чём сегодня поговорим - обработка вывода команд.
Помнишь, команда env выводит огромный список из переменных окружения. Можно глазами искать нужные данные в списке, но мы же с тобой знаем, что всегда найдётся способ сделать это лучше и удобнее!
Для этого в Linux есть специальный подход под названием pipe. Это способ передачи результата одной команды в другую для его обработки.
Если проще, что если я хочу из всего вывода env найти только те строки, которые содержат строку "HOME"?
Тогда мы берем env, символ "|" (pipe) и новую для нас команду grep, которая ищет строки, содержащие интересующий шаблон!
Попробуем:
env | grep "HOME"💪 Попробуй вывести те строки, которые содержат строку "PY".
Вау, круто! И я скажу больше, pipes можно складывать из любого количества команд!
💪 Выведи, сколько строк отображается командой env, воспользовавшись через pipe командой wc. У wc есть полезные опции для этого, посмотри справку.
- Краткий экскурс в пару команд управления файлами
- Как писать скрипты и делать их исполняемыми
- Как работать с переменными окружения и сессиями
- Как импортировать переменные из скрипта в сессию
- Как настраивать запуск терминала под свои нужды
- Как обрабатывать вывод от одной команды другими
В этой теме прошли только основы-основ, так то и в скриптах есть логические конструкции, циклы и т.д., и команд управления в разы больше, так что не останавливайтесь на этом, читайте статьи в интернете и пробуйте узнавать новое самостоятельно!


