Оболочка, пути и кавычки: что получает команда
В проекте есть файл lesson notes.txt. Вы вводите его имя в команду и получаете две ошибки: инструмент ищет lesson и notes.txt отдельно. Файл цел, а проблема возникла ещё до его открытия. Оболочка превратила строку в аргументы, которые не совпали с вашим намерением.
В прошлом уроке вы отличили shell от ядра. Сейчас посмотрим, как оболочка выбирает команду, подставляет значения и передаёт аргументы. Для упражнений используем Bash. Если текущая оболочка другая, выполните bash; команда exit позже вернёт в предыдущую. Возможности Bash не надо автоматически переносить на /bin/sh или PowerShell.
Где начинается путь
Абсолютный путь начинается с / и идёт от корня файловой системы. Относительный отсчитывается от текущего рабочего каталога процесса. . обозначает этот каталог, .. — его родителя. Домашний каталог текущего пользователя shell может подставлять вместо ~.
pwd
cd "$HOME"
pwd
ls .Кавычки вокруг $HOME сохраняют значение как один аргумент. cd меняет каталог текущей оболочки, но не двигает файлы. Пути ./report.txt и report.txt здесь называют один объект. После перехода в другой каталог тот же относительный путь может назвать уже другой файл.
Начнём отдельную лабораторию:
lab_dir=$(mktemp -d)
cd "$lab_dir"
mkdir 'project notes'
printf 'draft\n' > 'project notes/lesson notes.txt'
pwdmktemp -d создаёт новую временную папку и печатает её путь. Конструкция $(...) подставляет вывод команды. Переменная lab_dir хранит полученный путь. Он будет отличаться на разных машинах; не переписывайте пример буквальным /tmp-именем. Перенаправление > создаёт или перезаписывает файл, поэтому здесь оно используется только для нового учебного объекта.
Строка и аргументы
Shell разбивает команду на слова, обрабатывает кавычки и подстановки, затем запускает программу с аргументами. Кавычки обычно не передаются программе как часть имени: они управляют разбором строки. Одинарные кавычки сохраняют буквальный текст. Двойные допускают подстановку переменных, сохраняя результат одним аргументом.
name='lesson notes.txt'
printf '<%s>\n' "$name"
printf '<%s>\n' '$name'
cat "project notes/$name"Первый вывод — <lesson notes.txt>, второй — <$name>, а cat покажет draft. Команда printf выводит текст по заданному формату; %s обозначает строку. Кавычки различаются не красотой оформления, а правилами подстановки.
Некавыченная $name может разбиться по пробелам и подвергнуться раскрытию шаблонов. Это опасно для имён с пробелами, звёздочками и переводами строк. Для аргумента, который должен представлять одно значение, начинайте с "$name". Не пытайтесь лечить уже неправильно разобранное имя добавлением sudo.
Шаблон раскрывает shell
Звёздочка * в некавыченном слове подбирает подходящие имена текущего каталога. Это glob, не регулярное выражение и не команда поиска внутри файлов. Например:
printf 'a\n' > alpha.txt
printf 'b\n' > beta.txt
printf '%s\n' *.txt
printf '%s\n' '*.txt'Первый вызов обычно выводит alpha.txt и beta.txt, второй — буквальное *.txt. В Bash без дополнительных настроек шаблон без совпадений может остаться буквальным. Не стройте скрипт на предположении, что пустой поиск всегда даёт пустой список. Регулярные выражения для текста появятся позже.
Имена с начальным - некоторые программы принимают за опции. Путь ./-report.txt явно содержит имя файла, а многие GNU-инструменты поддерживают -- как конец опций. Это разные способы избежать неоднозначности. Поддержку конкретной команды проверяйте в справке, а не считайте любое -- универсальным.
Найти справку и команду
type cd
type printf
type cat
man pwdtype объясняет, встроена ли команда в shell, является ли псевдонимом или внешним файлом. Несколько команд одного имени могут существовать одновременно. В man обычно нажимают q для выхода, / для поиска. В минимальном образе справочник может отсутствовать; используйте официальный manual и вернитесь к установке пакетов в соответствующей главе.
Перед переходом дальше проверьте собственную привычку: сначала посмотреть pwd, затем назвать ожидаемый путь назначения и только потом выполнить команду. Относительный путь зависит от рабочего каталога, поэтому одна и та же строка может затронуть разные файлы после cd.
Самостоятельная лаборатория
Создайте подкаталог с пробелом и два файла: один с пробелом, другой со звёздочкой в имени. Покажите содержимое каждого по точному пути. Затем из родительского каталога найдите тот же объект абсолютным и относительным путём. Запишите аргументы, которые вы намеревались передать, до запуска команды.
Критерий готовности: ваша команда читает ровно выбранный файл, кавычки сохраняют одно имя, а pwd объясняет смысл относительного пути. Для проверки используйте printf '<%s>\n' ... вместо случайного копирования. Файл со звёздочкой должен читаться как буквальное имя, а не как весь набор совпадений.
Разбор
cat "$lab_dir/project notes/lesson notes.txt" работает независимо от текущего каталога, если переменная сохранилась. cat 'project notes/lesson notes.txt' работает из лабораторной папки. Новая оболочка не обязана знать вашу переменную — окружение изучим отдельно. Пока сохраните путь в заметке и оставьте лабораторию для исследования файлов.
Первичные источники: GNU Bash: quoting, Bash shell expansions, GNU Coreutils: pwd.