Символические ссылки: как создать и работать в Linux

Рано или поздно возникает ситуация, когда один и тот же файл нужен сразу в нескольких местах. Копировать его каждый раз – плохое решение: копии расходятся между собой, место на диске тратится впустую, а обновить их все одной командой и тем более быстро откатить изменения обратно не получится. В Linux для этого есть механизм полегче – символическая ссылка (symlink).

В этой статье разберем, что такое символические ссылки, чем они отличаются от жестких, что важно учитывать при работе с ними и как создавать, удалять и использовать symlink на практике – с командами, которые можно сразу проверить в терминале.

Что такое символические ссылки

Символическая ссылка (от англ. symbolic link, symlink, “симлинк”, “мягкая ссылка”) – это специальный файл, который не содержит данных сам по себе, а хранит путь к другому файлу или директории. По сути, это указатель: когда система или программа обращается к ней, она автоматически перенаправляется по пути, записанному внутри ссылки, к реальному объекту. Например, символическая ссылка на папку позволяет обращаться к каталогу из другого места, не создавая его копию.

Проще всего представить символические ссылки как ярлык в Windows или alias в macOS – только реализованный на уровне файловой системы Linux. Благодаря этому символическая ссылка работает одинаково для любой программы: текстового редактора, веб-сервера, команды cat или скрипта на PHP – все они видят ссылку и автоматически переходят по пути, записанному в ней, к реальному файлу или директории.

Важно понимать: символическая ссылка не хранит содержимое исходного файла и не занимает на диске место, сопоставимое с размером цели, – только текст самого пути. Именно поэтому к одному и тому же файлу или директории можно обращаться сразу из нескольких мест, не дублируя данные и не тратя на это лишнее место.

Жесткие и символические ссылки: в чем отличие

Кроме символической, в Linux есть еще один тип ссылок – жесткая ссылка (hard link). Она устроена совсем по-другому, и сравнение с ней хорошо показывает, что на самом деле представляет собой символическая ссылка и почему у нее именно такие возможности и ограничения.

Чтобы понять разницу, нужно вспомнить, как устроена файловая система Linux. В файловой системе каждый объект имеет inode (index node) – структуру данных, в которой хранятся его метаданные: владелец, права доступа, размер и другие сведения. При этом имя файла в inode не хранится – оно является частью записи каталога, которая связывает имя с конкретным inode.

Именно из этого принципа и вытекает, что такое жесткая ссылка: это не отдельный файл-указатель, как символическая ссылка, а еще одна запись в директории, которая указывает на тот же inode, что и оригинальный файл. И оригинал, и жесткая ссылки полностью равноправны и ведут к одним и тем же данным на диске – нельзя даже сказать, какое из имен “настоящее”, а какое “ссылка”.

Разница между жесткой (hard link) и символической (symlink) ссылками видна по нескольким параметрам:

  • Inode. У жесткой ссылки – тот же inode, что и у оригинала: это буквально второе имя того же файла. У symlink – собственный, отдельный inode: это самостоятельный файл, внутри которого хранится не содержимое, а путь к цели;
  • Ссылка на директорию. Жесткую ссылку на директорию создать нельзя – это стандартное ограничение файловых систем Linux, чтобы избежать циклов в дереве каталогов. У symlink этого ограничения нет: он может указывать как на файл, так и на директорию;
  • Работа между файловыми системами и разделами. Жесткая ссылка не может пересекать границу файловой системы – номера inode уникальны только в ее пределах. Symlink этого ограничения не имеет и может ссылаться на объект в другой файловой системе или на другом разделе;
  • Поведение при удалении или перемещении оригинала. У каждого inode есть счетчик количества жестких ссылок на него (поле st_nlink): данные физически удаляются, только когда счетчик доходит до нуля, то есть когда удалено последнее имя, под которым к файлу можно обратиться. Поэтому жесткая ссылка продолжает работать, даже если удалить “оригинал”, так как оригинал и ссылка равноправны. У symlink такого счетчика нет: если удалить, переименовать или переместить цель, ссылка сразу станет нерабочей (“битой”).

Разницу легко увидеть на практике. Если создать файл, жесткую и символическую ссылку на него и посмотреть на номера inode командой ls -li, вывод будет примерно таким:

~$ ls -li original.txt hardlink.txt symlink.txt
2963 -rw-rw-r-- 2 betutorial betutorial 33 Aug 17 14:38 hardlink.txt
2963 -rw-rw-r-- 2 betutorial betutorial 33 Aug 17 14:38 original.txt
3501 lrwxrwxrwx 1 betutorial betutorial 12 Aug 17 14:38 symlink.txt -> original.txt

У original.txt и hardlink.txt номер inode будет одинаковым, у symlink.txt – другим. Также в этом примере видно, что у жесткой ссылки в колонке размера отображается реальный размер файла (это те же данные на диске), а у symlink – длина пути, который в нем записан.

После удаления original.txt жесткая ссылка остается рабочей, а символическая – ломается:

~$ rm original.txt
~$ cat hardlink.txt
Это тестовый файл
~$ cat symlink.txt
cat: symlink.txt: No such file or directory

На практике из-за описанных ограничений жесткие ссылки используют редко и для узких задач (например, чтобы у одного и того же файла было сразу два имени в пределах одного раздела), а symlink – гораздо чаще, именно благодаря гибкости: возможности ссылаться на директории и работать между разными файловыми системами.

Как создать, удалить и обновить символическую ссылку

В этом разделе разберем, как создать символическую ссылку, удалить и обновить ее, и сразу проверим команды на практике.

Для этого создадим тестовую директорию с файлами:

~$ mkdir ~/symlink-test && cd ~/symlink-test
~/symlink-test$ mkdir project
~/symlink-test$ echo "Это тестовый файл" > project/notes.txt

Создание

Для создания такой ссылки используется команда ln с флагом -s:

ln -s <путь_к_цели> <имя_ссылки>

Создадим символическую ссылку на файл:

~/symlink-test$ ln -s project/notes.txt notes-link.txt
~/symlink-test$ ls -l notes-link.txt
lrwxrwxrwx 1 betutorial betutorial 17 Aug 18 08:13 notes-link.txt -> project/notes.txt
~/symlink-test$ cat notes-link.txt
Это тестовый файл

Ссылка на директорию делается точно так же – никакого отдельного флага не требуется:

~/symlink-test$ ln -s project project-link
~/symlink-test$ ls -l project-link
lrwxrwxrwx 1 betutorial betutorial 7 Aug 18 08:14 project-link -> project
~/symlink-test$ ls project
notes.txt
~/symlink-test$ ls project-link
notes.txt

Если нужно создать ссылку с тем же именем, что и у цели, но в другой директории, последний аргумент можно опустить – ln возьмет исходное имя файла:

~/symlink-test$ mkdir links && cd links
~/symlink-test/links$ ln -s ../project/notes.txt
~/symlink-test/links$ ls -l
total 0
lrwxrwxrwx 1 betutorial betutorial 20 Aug 18 08:15 notes.txt -> ../project/notes.txt
~/symlink-test/links$ cat notes.txt
Это тестовый файл

Удаление

Удалить символическую ссылку можно командой rm или unlink. Обе команды могут удалить символическую ссылку, но отличаются набором возможностей:

  • rm – может удалить сразу несколько ссылок за один вызов и поддерживает шаблоны (*);
  • unlink – может удалить ровно одну ссылку за раз, шаблоны не поддерживает.

Проверим удаление символических ссылок:

~/symlink-test$ rm notes-link.txt
~/symlink-test$ ls -l
total 8
drwxrwxr-x 2 betutorial betutorial 4096 Aug 18 08:15 links
drwxrwxr-x 2 betutorial betutorial 4096 Aug 18 08:13 project
lrwxrwxrwx 1 betutorial betutorial    7 Aug 18 08:14 project-link -> project
~/symlink-test$ unlink project-link
~/symlink-test$ ls -l
total 8
drwxrwxr-x 2 betutorial betutorial 4096 Aug 18 08:15 links
drwxrwxr-x 2 betutorial betutorial 4096 Aug 18 08:13 project

При удалении символической ссылки ее цель (файл или директория) не удаляется.

Обратите внимание!
Если путь к символической ссылке на директорию заканчивается на /, система воспринимает такой путь как обращение к директории, на которую указывает ссылка, а не к самой ссылке. Поэтому при удалении символической ссылки завершающий / лучше не указывать.

Протестируем удаление символической ссылки на директорию с указанием / и без него. Ссылку project-link мы уже удалили выше, поэтому создадим ее заново и попробуем удалить сначала со слэшем, потом без него:

~/symlink-test$ ln -s project project-link
~/symlink-test$ ls -l project-link
lrwxrwxrwx 1 betutorial betutorial 7 Aug 18 08:18 project-link -> project
~/symlink-test$ rm project-link/
rm: cannot remove 'project-link/': Is a directory
~/symlink-test$ rm project-link
~/symlink-test$ ls -l
total 8
drwxrwxr-x 2 betutorial betutorial 4096 Aug 18 08:15 links
drwxrwxr-x 2 betutorial betutorial 4096 Aug 18 08:13 project

Симлинк на директорию нельзя удалить командой rmdir – она предназначена только для настоящих пустых директорий и вернет ошибку Not a directory.

Обновление уже существующей символической ссылки

Отдельная задача – не создать символическую ссылку с нуля, а переключить уже существующую на новую цель. Команда используется одна и та же, но изменяются флаги.

Пример с файлом. Пусть ссылка config.php указывает на старый конфиг, и нужно переключить ее на новый:

~/symlink-test$ echo "старый конфиг" > config-old.php
~/symlink-test$ echo "новый конфиг" > config-new.php
~/symlink-test$ ln -s config-old.php config.php
~/symlink-test$ ls -l config.php
lrwxrwxrwx 1 betutorial betutorial 14 Aug 18 08:21 config.php -> config-old.php
~/symlink-test$ cat config.php
старый конфиг

Просто повторить ln -s не получится – имя config.php уже занято:

~/symlink-test$ ln -s config-new.php config.php
ln: failed to create symbolic link 'config.php': File exists
Обратите внимание!
Такая же ошибка появится и в том случае, если с этим именем создан обычный файл, а не ссылка. Прежде чем перезаписывать символическую ссылку, проверьте командой ls -l, что имя действительно принадлежит ссылке, а не файлу с данными.

Для перезаписи ссылки добавляем флаг -f (--force, “принудительно”) – он указывает ln не выдавать ошибку, а удалить существующий файл или ссылку с этим именем и создать на его месте новую:

~/symlink-test$ ln -sf config-new.php config.php
~/symlink-test$ ls -l config.php
lrwxrwxrwx 1 betutorial betutorial 14 Aug 18 08:23 config.php -> config-new.php
~/symlink-test$ cat config.php
новый конфиг

Пример с директорией. Пусть current указывает на директорию release-1:

~/symlink-test$ mkdir release-1 release-2
~/symlink-test$ echo "версия 1" > release-1/version.txt
~/symlink-test$ echo "версия 2" > release-2/version.txt
~/symlink-test$ ln -s release-1 current
~/symlink-test$ ls -l current
lrwxrwxrwx 1 betutorial betutorial 9 Aug 18 08:23 current -> release-1
~/symlink-test$ cat current/version.txt
версия 1

Попробуем переключить current на release-2 тем же способом:

~/symlink-test$ ln -sf release-2 current
~/symlink-test$ ls -l current
lrwxrwxrwx 1 betutorial betutorial 9 Aug 18 08:23 current -> release-1
~/symlink-test$ cat current/version.txt
версия 1

Символическая ссылка current не изменилась. Утилита ln обнаружила, что current ведет на директорию, перешла внутрь нее, создав там новую ссылку с именем release-2 – вместо того, чтобы заменить симлинк current:

~/symlink-test/release-1$ ls -l
total 4
lrwxrwxrwx 1 betutorial betutorial  9 Aug 18 08:24 release-2 -> release-2
-rw-rw-r-- 1 betutorial betutorial 15 Aug 18 08:23 version.txt

Чтобы заменить именно current, а не создать ссылку внутри ее цели, нужен еще один флаг – -n (--no-dereference, “не переходить по ссылке”) – он указывает ln воспринимать current как обычное имя, а не заходить внутрь директории, на которую эта ссылка сейчас указывает:

~/symlink-test$ ln -sfn release-2 current
~/symlink-test$ ls -l current
lrwxrwxrwx 1 betutorial betutorial 9 Aug 18 08:26 current -> release-2
~/symlink-test$ cat current/version.txt
версия 2

Ту же задачу можно решить и проще – удалить старую ссылку и создать новую:

rm current
ln -s release-2 current

Для тестов и разовых задач данный способ подойдет. Для боевого сервера, где current – это, например, document root работающего сайта, у такого способа есть нюанс: между rm и ln -s есть короткий промежуток времени, когда пути current не существует вообще, и случайный запрос в это время может получить ошибку. Команда ln -sfn заменяет ссылку одной операцией без простоя.

У симлинка есть несколько особенностей поведения, из-за которых он может повести себя не так, как ожидается. 

Чтобы не путать эти примеры с уже созданными файлами и ссылками, создадим для них отдельную тестовую директорию:

~$ mkdir ~/symlink-test2 && cd ~/symlink-test2
~/symlink-test2$ echo "Это тестовый файл" > notes.txt

Абсолютный или относительный путь. Ссылку можно создать с абсолютным путем или относительным. Это важно при переносе файлов: относительная ссылка останется рабочей, если переместить и ссылку, и цель в новое место вместе, сохранив их взаимное расположение, а абсолютная – только если не менять расположение самой цели.

~/symlink-test2$ ln -s "$(pwd)/notes.txt" abs-link.txt
~/symlink-test2$ ln -s notes.txt rel-link.txt
~/symlink-test2$ readlink abs-link.txt
/home/betutorial/symlink-test2/notes.txt
~/symlink-test2$ readlink rel-link.txt
notes.txt

Видно, что readlink возвращает именно тот путь, который был записан в ссылку при создании, – в первом случае полный, во втором относительный.

Symlink можно создать на несуществующую цель. Linux не проверяет при создании символической ссылки, существует ли путь, на который она указывает, – ошибки не будет, даже если будет опечатка в пути:

~/symlink-test2$ ln -s not-yet-created.txt future-link.txt
~/symlink-test2$ ls -l future-link.txt
lrwxrwxrwx 1 betutorial betutorial 19 Aug 18 11:38 future-link.txt -> not-yet-created.txt
~/symlink-test2$ cat future-link.txt
cat: future-link.txt: No such file or directory

Ссылка может стать “битой” в любой момент своей жизни – если цель удалили, переименовали или переместили. Найти все битые ссылки в директории можно при помощи утилиты find:

~/symlink-test2$ find . -xtype l
./future-link.txt
А потом узнать, куда именно ведет конкретная ссылка:
~/symlink-test2$ readlink future-link.txt
not-yet-created.txt
~/symlink-test2$ readlink -f future-link.txt
/home/betutorial/symlink-test2/not-yet-created.txt

readlink возвращает путь ровно в том виде, в каком он записан в ссылке, а readlink -f разворачивает его в полный абсолютный путь.

Symlink может указывать на другую ссылку, образуя цепочку. Система разворачивает такие цепочки автоматически, но если ссылки образуют цикл (ссылаются друг на друга), при обращении к ним будет ошибка:

~/symlink-test2$ ln -s notes.txt chain1.txt
~/symlink-test2$ ln -s chain1.txt chain2.txt
~/symlink-test2$ readlink chain2.txt
chain1.txt
~/symlink-test2$ readlink -f chain2.txt
/home/betutorial/symlink-test2/notes.txt
~/symlink-test2$ ln -s loop2.txt loop1.txt
~/symlink-test2$ ln -s loop1.txt loop2.txt
~/symlink-test2$ cat loop1.txt
cat: loop1.txt: Too many levels of symbolic links

Примеры использования символических ссылок

Рассмотрим несколько типичных задач, в которых symlink находит применение на практике:

  1. Обновление сайта без остановки (деплой релизов)

Каждая версия сайта разворачивается в отдельную директорию с номером или датой релиза, а на актуальную указывает единый symlink current – именно он настроен как document root веб-сервера:

ln -sfn /var/www/site/releases/2026-08-15 /var/www/site/current

Обновление сводится к одной команде – переключить ссылку на новый релиз. Откат к предыдущей версии делается точно так же, без повторной выгрузки файлов. Благодаря этому переключение происходит мгновенно и без простоя.

  1. Переключение между версиями Python, Node.js и других сред

Если на сервере установлено несколько версий одного языка или рантайма (например, /opt/node-18 и /opt/node-20), удобно не переписывать пути в каждом проекте или скрипте при переходе на новую версию, а один раз добавить символическую ссылку и переключать ее:

ln -sfn /opt/node-20 /usr/local/node

Все проекты и скрипты обращаются к /usr/local/node/bin/node и не знают, какая версия установлена на самом деле. Перейти на другую версию – значит перелинковать одну ссылку, а не искать и менять путь во всех местах, где он был прописан. Если новая версия окажется несовместимой, откат назад – снова одна команда.

  1. Хранение загружаемых файлов на отдельном диске

Когда файлы, которые загружают пользователи, растут быстрее, чем код приложения, их удобно вынести на отдельный диск или раздел, а в директории сайта оставить только ссылку:

ln -s /mnt/storage/uploads /var/www/site/uploads

Код приложения продолжает работать с привычным путем uploads/, ничего в нем менять не нужно, а хранилище можно расширять независимо от диска с самим сайтом.

  1. Включение и отключение сайтов в Nginx

В Debian и Ubuntu конфигурации сайтов принято хранить в sites-available, а подключать – символической ссылкой из sites-enabled:

ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/example.com.conf

Отключить сайт – значит просто удалить ссылку, не трогая сам файл конфигурации. Это удобнее, чем закомментировать блок server или хранить несколько версий одного конфига: включение и отключение сайта не требуют правок самого файла и не рискуют испортить его синтаксис.

Заключение

Symlink – это простой указатель на другой файл или директорию: не копия, а еще один путь к тем же данным. В отличие от жесткой ссылки, он может вести на директорию и работать между разными дисками и разделами, но зато способен “сломаться”, если цель удалят или переместят.

Для повседневной работы достаточно нескольких команд: ln -s – создать ссылку, ln -sfn – заменить существующую, rm или unlink – удалить, readlink -f – проверить, куда она ведет, даже если цель не существует. С этим набором symlink пригодится и для деплоя, и для организации файлов на сервере, и для десятков других задач, где не хочется дублировать данные.

Если возникнут вопросы, напишите нам, пожалуйста, тикет из панели управления аккаунта (раздел “Помощь и поддержка”), а если вы захотите обсудить эту статью или наши продукты с коллегами по цеху и сотрудниками Beget – ждем вас в нашем сообществе в Telegram.