Четыре маленькие утилиты для работы с путями. basename и dirname режут строку пути и не обращаются к диску. realpath и readlink смотрят в файловую систему: раскрывают символические ссылки, . и ... В довесок — namei, который показывает каждый шаг пути с правами. В песочнице — GNU coreutils 9.4 и util-linux.
Синтаксис
basename путь [суффикс]
basename -a [-s суффикс] путь…
dirname путь…
realpath [опции] путь…
readlink [опции] ссылка…
namei [опции] путь…
basename — последняя часть пути
| Вызов | Результат |
|---|
basename /var/log/nginx/access.log | access.log |
basename /var/log/nginx/access.log .log | access — суффикс отрезан |
basename /var/log/ | log — косая черта в конце игнорируется |
basename / | / |
basename .log .log | .log — суффикс не отрезается, если он равен всему имени |
| Опция | Что делает |
|---|
-s суффикс | отрезать суффикс; подразумевает -a |
-a | принять несколько путей, по результату на строку |
-z | разделять результаты нулевым байтом |
dirname — всё, кроме последней части
| Вызов | Результат |
|---|
dirname /var/log/nginx/access.log | /var/log/nginx |
dirname file.txt | . — текущий каталог |
dirname /var/log/ | /var |
dirname / | / |
dirname a/b c/d | a и c — по строке на путь |
realpath — канонический абсолютный путь
Раскрывает все ссылки, ., .. и лишние /. По умолчанию все компоненты, кроме последнего, должны существовать.
| Опция | Что делает |
|---|
| (без опций) | физический путь: ссылки раскрыты, последний компонент может не существовать |
-e | все компоненты обязаны существовать, иначе ошибка |
-m | ничего не обязано существовать — чисто строковая нормализация |
-s | не раскрывать ссылки, только убрать ., .., // |
-L | сначала обработать .., потом ссылки (как cd/pwd в bash) |
-P | сначала ссылки, потом .. (по умолчанию) |
--relative-to=каталог | вывести путь относительно каталога |
--relative-base=каталог | относительный путь, только если цель внутри каталога; иначе абсолютный |
-q | не печатать ошибки |
-z | разделять результаты нулевым байтом |
readlink — содержимое символической ссылки
| Опция | Что делает |
|---|
| (без опций) | путь, записанный в ссылке, как есть (может быть относительным). Не ссылка — пусто и код 1 |
-f | канонический путь: раскрыть все ссылки рекурсивно; последний компонент может не существовать |
-e | как -f, но всё должно существовать |
-m | как -f, но ничего не обязано существовать |
-n | не печатать перевод строки в конце |
-v | сообщать об ошибках (по умолчанию readlink молчит) |
readlink -f и realpath почти одинаковы; realpath нагляднее и умеет относительные пути.
namei — разбор пути по шагам
Показывает каждый компонент пути, его тип и куда ведут ссылки. Главное применение — понять, на каком каталоге пути не хватает прав.
| Опция | Что делает |
|---|
-l | длинный формат: права + владелец + группа (-m -o -v) |
-m | права каждого компонента |
-o | владелец и группа |
-x | точки монтирования помечать D вместо d |
-n | не раскрывать символические ссылки |
$ namei -l /etc/os-release
f: /etc/os-release
drwxr-xr-x root root /
drwxr-xr-x root root etc
lrwxrwxrwx root root os-release -> ../usr/lib/os-release
drwxr-xr-x root root ..
drwxr-xr-x root root usr
drwxr-xr-x root root lib
-rw-r--r-- root root os-release
Примеры
# имя файла без расширения
basename /data/report.csv .csv
# отрезать суффикс у нескольких путей
basename -s .log /var/log/app.log /var/log/db.log
# каталог, где лежит сам скрипт (работает при вызове из любого места)
script_dir=$(dirname "$(realpath "$0")")
# куда указывает ссылка: как записано и итоговый путь
readlink /srv/app/current
readlink -f /srv/app/current
# путь из одного каталога в другой — для ln -s
realpath --relative-to=/etc /var/log
# нормализовать путь, которого ещё нет
realpath -m /srv/app/../data//new
# почему пользователь не может прочитать файл: права на каждом шаге
namei -l /srv/app/config/secret.yml
# то же без внешних команд — средствами bash
f=/srv/app/data.tar.gz
echo "${f##*/}" # data.tar.gz — как basename
echo "${f%/*}" # /srv/app — как dirname
Подводные камни
basename/dirname не знают о файловой системе. dirname ссылка вернёт каталог ссылки, а не цели. Для реального места — realpath.
readlink без -f возвращает путь как записан — часто относительный (../current/x) и считается от каталога ссылки, а не от текущего.
readlink на обычном файле молча печатает пусто и возвращает 1. С -v видно причину: «Invalid argument».
realpath и несуществующие каталоги. realpath /no/such — ошибка, потому что нет /no. Если нужна только нормализация строки — -m.
.. и ссылки. Если current — ссылка на releases/v2, то realpath current/.. даст /srv/app/releases (физически), а realpath -L current/.. и cd current/.. — /srv/app.
- Суффикс у
basename — это строка, а не шаблон: basename a.tar.gz .gz → a.tar, а '*.gz' ничего не отрежет.
- Пробелы. Всегда бери в кавычки и аргумент, и подстановку:
dirname "$(realpath "$0")".
См. также
ln · ls · stat · chmod · variables · find