Зачем нужен скрипт
Мы уже умеем выполнять команды по одной: набрали date, получили дату, набрали pwd, увидели каталог. Это удобно, пока действий мало. Но представьте, что каждое утро вы начинаете работу одинаково: хотите посмотреть дату, текущий каталог и, скажем, список файлов. Три команды — не так уж много. А если бы их было десять? Или двадцать? Каждый раз вводить их заново — скучно и легко ошибиться: то опечатка, то не та опция.
Именно для такой повторяющейся работы и существуют скрипты. Скрипт — это обычный текстовый файл, в котором команды записаны заранее, одна за другой. Вместо того чтобы набирать их вручную, мы запускаем файл, и оболочка выполняет всё, что в нём написано. По сути, это та же командная строка, только растянутая не по времени, а по строкам файла.
Сегодня мы создадим первый скрипт. Он будет совсем небольшим: покажет заголовок, дату и рабочий каталог. Никаких сложных операций, только то, что мы уже знаем. Зато мы разберёмся, как такой файл запускать и что при этом происходит.
Создаём каталог для скриптов
До сих пор у нас были каталоги для файлов, потоков и прав доступа. Теперь появится новый проект — скрипты. Чтобы не смешивать его со старыми учебными материалами, создадим свежий каталог ~/linux-scripts.
Сначала проверим, что имя свободно:
ls -ld ~/linux-scripts
Если команда сообщит об ошибке «No such file or directory» — отлично, каталога ещё нет, и мы можем создать его. Если же такой каталог вдруг существует, выберите другое имя, например ~/linux-scripts-2, и используйте его дальше во всех командах. В нашей ситуации каталога нет, поэтому продолжаем с ~/linux-scripts.
Создадим каталог:
mkdir ~/linux-scripts
Команда выполнится без вывода. Это нормально: mkdir молчит, если всё прошло успешно. Перейдём в новый каталог:
cd ~/linux-scripts
Теперь наш рабочий каталог — свежая папка для скриптов. Проверим, что мы действительно там:
pwd
Вывод покажет /home/student/linux-scripts или /home/ubuntu/linux-scripts, в зависимости от имени вашей учётной записи. Всё готово.
Пишем первый скрипт
Для создания файла мы используем уже знакомый редактор nano. Назовём файл report.sh:
nano report.sh
Откроется пустой редактор. Наберём в нём такой текст:
#!/bin/bash
printf '%s\n' 'Study report'
date +%Y-%m-%d
printf 'Working directory: '
pwd
Разберём, что здесь написано, по порядку. Первая строка — #!/bin/bash. Она называется shebang. Слово происходит от двух символов, с которых начинается строка: решётка # и восклицательный знак !. Вместе их произносят как «sha-bang» или «she-bang». Эта строка сообщает операционной системе, какую программу нужно вызвать, чтобы выполнить содержимое файла. Мы указываем /bin/bash — путь к интерпретатору Bash, той самой оболочке, в которой мы работаем.
Обратите внимание: символ # в Bash обычно начинает комментарий — текст, который оболочка игнорирует. Но именно в первой строке, когда за решёткой сразу идёт восклицательный знак, эта строка получает особый смысл. Она работает не как комментарий внутри скрипта, а как подсказка для системы при запуске файла. Для самой оболочки, когда она уже читает файл, строка с shebang действительно выглядит как комментарий и пропускается. Но для операционной системы, которая решает, чем открывать файл, она важна.
Вторая строка — printf '%s\n' 'Study report'. Это знакомая нам команда с форматом %s\n, который печатает строку и добавляет перевод на новую строку. В скрипте она выведет заголовок Study report.
Третья строка — date +%Y-%m-%d. Мы уже использовали этот формат в практике с отчётом: он показывает дату в виде год-месяц-день, например 2026-09-09.
Четвёртая строка — printf 'Working directory: '. Обратите внимание: здесь нет %s и нет \n. Мы просто печатаем текст без перевода строки, чтобы следующая команда дописала свой вывод в ту же строку. Дальше идёт команда pwd, которая выводит текущий каталог. Вместе эти две строки дадут, например, Working directory: /home/student/linux-scripts — подпись и значение на одной строке.
Почему форматы двух вызовов printf отличаются? В первом случае мне нужен перевод строки после текста, поэтому я использую %s\n. Во втором случае перевод строки как раз не нужен: я хочу, чтобы pwd дописал каталог сразу после двоеточия и пробела, а pwd сама поставит перевод строки в конце. Оба варианта нам уже знакомы по работе с выводом.
После того как набрали текст, сохраняем файл и выходим из nano. Мы помним, как это делается: Ctrl+O для сохранения, Enter для подтверждения имени, Ctrl+X для выхода.
Расширение .sh в имени файла — не обязательное требование. Bash не смотрит на расширение, чтобы понять, что делать с файлом. Ему важно содержимое, а не суффикс. Мы могли бы назвать файл просто report или first-script, и при правильном запуске он всё равно выполнился бы. Расширение .sh — это соглашение, которое помогает нам, людям, сразу видеть, что перед нами shell-скрипт. Оно удобно, но не является правилом.
Можно добавить в скрипт и комментарий для человека. Например, строка # Печатает отчёт объяснила бы, зачем нужны следующие команды. Она начинается с решётки, поэтому Bash её игнорирует. В нашем первом скрипте всё и так понятно, но комментарии — хорошая привычка на будущее. Важно не путать: shebang — это не любой комментарий, а именно первая строка, и у неё особая роль при запуске.
Проверим, что файл создался:
ls -l report.sh
Вывод покажет имя файла, его размер, владельца и права. Обратите внимание на права: пока что там, скорее всего, rw-rw-r-- или rw-r--r--. Буквы x нигде нет. Это означает, что файл можно читать и изменять, но нельзя выполнять напрямую. Сейчас мы разберёмся, как это влияет на запуск.
Запуск через интерпретатор
Самый простой способ выполнить скрипт — явно вызвать Bash и передать ему имя файла:
bash report.sh
Здесь мы запускаем программу bash и говорим ей: прочитай файл report.sh и выполни все команды из него. В этом случае файлу не нужны права на выполнение. Достаточно, чтобы Bash мог прочитать его содержимое. Право на чтение у нас есть, поэтому команда сработает.
Вывод будет таким:
Study report
2026-09-09
Working directory: /home/student/linux-scripts
Дата будет той, что наступила в день запуска. Если вы выполните команду завтра, она покажет завтрашнее число. Это не ошибка: скрипт честно берёт текущую дату у системы.
Что произошло за кулисами? Мы запустили программу bash и передали ей аргумент — имя файла. Bash открыл файл, прочитал его построчно и выполнил команды так, как будто мы вводили их с клавиатуры. При этом строка #!/bin/bash не вызвала никаких действий: для Bash это просто комментарий в первой строке. Интерпретатор уже запущен нами явно, и shebang ему не нужен. Она пригодится в другом способе запуска.
Запуск как программы
Теперь попробуем запустить скрипт напрямую, без слова bash в начале:
./report.sh
Команда выдаст ошибку: Permission denied — «отказано в доступе». Почему? Потому что мы пытаемся выполнить файл как программу, а у него нет права на выполнение. Помните, в ls -l не было буквы x в правах. Система честно отказывается запускать файл, который не помечен как исполняемый.
Добавим это право. Мы уже знаем команду chmod и разбирались с правами доступа. Для нашего файла достаточно права выполнять для владельца:
chmod u+x report.sh
Эта команда добавляет владельцу право x на выполнение. Проверим:
ls -l report.sh
Теперь в правах появилась буква x. Например, вывод может быть rwxr--r-- или rwxrw-r-- — точный вид зависит от вашей umask, но главное, что у владельца право выполнять появилось.
Попробуем снова запустить напрямую:
./report.sh
Теперь скрипт выполнится и покажет тот же вывод, что и при запуске через bash report.sh. Разница в том, кто решает, чем открывать файл. Когда мы набираем ./report.sh, мы не указываем программу. Мы говорим системе: запусти этот файл. Система смотрит на первую строку, видит #!/bin/bash и понимает: нужно вызвать /bin/bash, передав ему путь к файлу. Shebang срабатывает именно здесь.
Символы ./ перед именем — это не украшение. Они задают явный путь к файлу: «в текущем каталоге». Если набрать просто report.sh, оболочка будет искать программу с таким именем в каталогах из переменной PATH. В нашем учебном маршруте текущий каталог в PATH не добавлялся. В произвольной системе это стоит проверить, а явный путь ./report.sh в любом случае указывает нужный файл. Мы помним это из урока про переменные окружения. Если каталог со скриптом отсутствует в PATH, запуск по одному имени report.sh завершится сообщением «command not found». А ./report.sh указывает точно: здесь, в этой папке, лежит наш скрипт. Обратите внимание: в ~/linux-scripts и в /home/student/linux-scripts суть одна, просто ~ — это сокращение для домашнего каталога. Набирая ./report.sh, мы находимся в этом каталоге, поэтому файл находится.
В нашей Ubuntu путь к Bash — именно /bin/bash. Это стандартное расположение интерпретатора в этой системе. В других Unix-системах Bash может находиться в другом месте, например /usr/bin/bash. Но в Ubuntu можно смело указывать /bin/bash, как мы и сделали в shebang.
Рабочий каталог скрипта
Скрипт не живёт сам по себе. Когда мы запускаем его, оболочка создаёт дочерний процесс, и этот процесс наследует настройки запускающей оболочки, включая её текущий рабочий каталог. Это отдельное свойство процесса, а не просто переменная окружения. Это важно понимать: место хранения файла скрипта не задаёт его рабочий каталог автоматически. При запуске рабочий каталог наследуется от родителя.
Проверим это. Сейчас мы находимся в ~/linux-scripts, и наш скрипт показывает именно этот каталог. А теперь перейдём в домашний каталог и запустим скрипт оттуда:
cd ~
bash ~/linux-scripts/report.sh
Мы указали полный путь к скрипту, поэтому Bash его найдёт, хотя мы и не находимся рядом с ним. Но что выведет pwd внутри скрипта? Каталог запуска, то есть домашний каталог /home/student, а не /home/student/linux-scripts. Скрипт унаследовал рабочий каталог от той оболочки, из которой мы его запустили. Мы запустили из дома — и скрипт видит дом.
Это частая точка путаницы. Кажется: скрипт лежит в linux-scripts, значит, и работает он там. Но нет. Место, где лежит файл, и рабочее место процесса — разные вещи. Файл — это просто текст, который лежит на диске. А рабочий каталог — это свойство запущенного процесса, которое он получил от родителя. Наш pwd печатает рабочий каталог процесса, а не каталог, где лежит скрипт.
Вернёмся в каталог скриптов:
cd ~/linux-scripts
Теперь снова запустим напрямую:
./report.sh
Вывод снова покажет linux-scripts как рабочий каталог, потому что мы запустили скрипт из него.
Кстати, раз мы заговорили о дочерних процессах: если бы скрипт сам менял каталог через cd, это изменение касалось бы только его процесса. Исходная оболочка осталась бы в своём каталоге. Мы это уже понимаем по работе с процессами: смена каталога в дочернем процессе не меняет текущий каталог родительской оболочки. Но в нашем первом скрипте нет cd, поэтому и проверять нечего. Он только читает окружение — и показывает, что унаследовал.
Что мы получили
У нас появился первый скрипт report.sh. Он печатает заголовок, текущую дату и рабочий каталог. Мы умеем запускать его двумя способами: явно через bash report.sh и напрямую через ./report.sh после добавления права на выполнение. И мы понимаем разницу между этими способами.
При явном запуске bash report.sh мы сами выбрали интерпретатор. Файлу не нужны права на выполнение, достаточно права на чтение. Shebang в этом случае не играет роли: Bash уже запущен, он читает файл, и строка #!/bin/bash для него — просто комментарий. При прямом запуске ./report.sh система смотрит на shebang, находит /bin/bash и вызывает его, передавая наш файл. Для этого файл должен быть помечен как исполняемый.
Оба способа дают одинаковый результат, но знание о разнице пригодится. В следующих уроках мы будем запускать скрипты по-разному, и важно понимать, что происходит в каждом случае. Пока наш скрипт совсем простой: он не принимает никаких данных, не хранит значения и не принимает решений. Всё это появится дальше, по одному шагу.
Скрипт — это текстовый файл с командами, которые оболочка выполняет по порядку. Мы создали report.sh в новом каталоге ~/linux-scripts с помощью nano, записали в него shebang #!/bin/bash и знакомые команды для вывода заголовка, даты и рабочего каталога. Shebang нужен при прямом запуске файла: по нему система определяет, что файл должен выполнять интерпретатор /bin/bash. Расширение .sh — не требование, а удобное соглашение для человека.
Запускать скрипт можно двумя способами. Команда bash report.sh явно вызывает Bash и передаёт ему файл: право на выполнение не нужно, достаточно чтения, а shebang не переключает уже запущенный интерпретатор. Команда ./report.sh требует право на выполнение, которое мы добавили через chmod u+x. При запуске по одному имени файл должен находиться в каталоге из PATH, а ./ позволяет явно выбрать скрипт в текущем каталоге. Рабочий каталог скрипта — это каталог, из которого его запустили, а не каталог, где лежит сам файл: после cd ~ и запуска bash ~/linux-scripts/report.sh скрипт показал домашний каталог, потому что унаследовал его от запускающей оболочки.
Подготовьте отдельный сценарий для практики и сравните способы его запуска. Учебный проект из теории менять не нужно: в заданиях используется новый каталог ~/bash-practice-start. Команды и содержимое файлов можно прислать как решение без выполнения.
Создание скрипта с shebang
Начните с чистого листа: создайте каталог для скриптов и файл первого сценария.
В домашнем каталоге ещё нет bash-practice-start. Запишите команды создания этого каталога и файла report.sh внутри него, а затем полный текст сценария. Он должен запускаться Bash и выводить три строки: Study report, текущую дату YYYY-MM-DD и Working directory: с текущим рабочим каталогом. Можно использовать редактор или другой корректный способ записи файла.
Прямой запуск и права
Теперь скрипт существует, попробуйте запустить его без явного вызова bash.
Вы находитесь в ~/bash-practice-start, файл report.sh создан. Запишите команду прямого запуска скрипта и ожидаемый результат при первом выполнении. Затем запишите, как исправить ситуацию и запустить скрипт снова. Объясните, что изменилось в правах файла. Для этого примера файл принадлежит вам, содержит корректный shebang и имеет режим 600; проход по каталогам разрешён.
Рабочий каталог при запуске из другого места
Проверим, как скрипт выбирает рабочий каталог, когда его запускают не из той папки, где он лежит.
Что напечатает pwd внутри скрипта при запуске bash ~/bash-practice-start/report.sh из домашнего каталога?