How to list all symbolic links in a directory
I have a symbolic link in my /var/www/ directory that links to WordPress. When I run the command ls -la from the /var/www/ directory the link to WordPress doesn’t show up. Is there a way to list all of the symbolic links that are in a directory?
10 Answers 10
Parsing ls is a Bad Idea®, prefer a simple find in that case:
To only process the current directory:
find . -maxdepth 1 -type l -ls
Great answer! I adjusted mine to not descend down directory path like this: find /
@GabrielStaples from man find: -ls True; list current file in ls -dils format on standard output. Useful to see ./os-release -> ../usr/lib/os-release in /etc rather than just ./os-release
You can use grep with ls command to list all the symbolic links present in the current directory.
This will list all the links present in the current directory.
Please, do not use ls for scripting. Also mentioned in other answers. More: mywiki.wooledge.org/ParsingLs
ls -lhaF | grep ^l # list links ls -lhaF | grep ^d # list directories ls -lhaF | grep ^- # list files
This will list lines starting with «l» which represent Links in the perms column in place of l use d for directories and — for files
Just don’t do anything with this method programatically since malicious filenames can end up injecting shell code. To be safe, one should use the find command with -exec , and if piping to xargs , use the null-character separator output flag of find combined with the null-character separator input flag of xargs .
@MtlDev ! negates the condition matching, here ! -name . means matching everything except current directory.
This returns all symbolically linked items (both dirs & fns) in a directory:
find . -maxdepth 1 -type l -print | cut -c3- | grep -v "\#"
However, in order to distinguish between actual symbolically linked item types:
ls -lhaF | grep ^l | grep -v "\#" | cut -c42- | grep -v "/" | cut -d' ' -f1
Returns symbolically linked filename items only. And,
ls -lhaF | grep ^l | grep -v "\#" | cut -c42- | grep "/" | cut -d' ' -f1
Returns symbolically linked dirname items only.
To view the symbolic links in a directory:
- Open a terminal and move to that directory.
- Type the command:
ls -l *(@) lrwxrwxrwx 1 david david 15 Nov 18 22:35 gvimrc -> /etc/vim/gvimrc lrwxrwxrwx 1 david david 13 Nov 18 22:19 mydomains.php -> mydomains.php
Type ls -lai ,it will list all the files and subdirectories with corresponding inode numbers.You know files with same inode number are the links(hard or soft) and this solution also works for the symbolic links.
ls -lai does not show the same inode number for a file and its symbolic links. Unlike hard links, symbolic links have their own separate inode entries. This is what it looks like.
Can be done with python as well:
$ python -c "import os,sys; print '\n'.join([os.path.join(sys.argv[1],i) for i in os.listdir(sys.argv[1]) if os.path.islink(os.path.join(sys.argv[1],i))])" /path/to/dir
$ python -c "import os,sys; print '\n'.join([os.path.join(sys.argv[1],i) for i in os.listdir(sys.argv[1]) if os.path.islink(os.path.join(sys.argv[1],i))])" /etc /etc/vtrgb /etc/printcap /etc/resolv.conf /etc/os-release /etc/mtab /etc/localtime
This can be extended to be recursive via os.walk function, but it’s sufficient to use simple list generation for listing links in a single directory as I showed above.
Sysadminium
В предыдущей статье мы познакомились с разными типами файлов в Linux, в этой статье подробнее разберем ссылки в этой операционной системе.
Теория
Файлы и каталоги на жестком диске хранятся в виде набора блоков. Информация о файле (метаданные), например время создания файла, хранится в индексном дескрипторе — inode. Номер inode является уникальным на файловой системе и связывается с определенным набором блоков.
А имя файла это всего лишь понятное для человека наименование которое относится к определенному inode.
Каталог — это файл особого типа в котором содержится список имен файлов или других каталогов и указатели на inode для этих файлов.
Ссылки в LInux — это дополнительные записи в каталоге, позволяющие обращаться к файлам или каталогам по другим именам. В Linux различают два вида ссылок:
- Жесткая — дополнительная запись в каталоге указывающая на уже созданный inode.
- Символьная — запись в каталоге указывающая на свой inode, но при чтении ссылающая на другой файл. При этом ссылается на другой файл по имени а не по inode.
Чтобы было понятнее посмотрите на следующий рисунок:
Есть файл с именем test1.txt и он имеет свой уникальный индексный дескриптор (inode 234), который ссылается на набор блоков (набор блоков 1) на жестком диске.
Файл test2.txt это жесткая ссылка. То есть, просто, дополнительное имя файла, которое ссылается на тот же inode что и test1.txt.
Файл test3.txt это символьная ссылка. Этот файл имеет свой индексный дескриптор (inode 465), и обращается к своему набору блоков (набор блоков 2). Этот файл является файлом отдельного типа (символьная ссылка / symbolic link) и в наборе данных у таких файлов записан путь к файлу на который она ссылается. То есть, в файле test3.txt указано что ссылаться нужно на test2.txt. При этом, если удалить файл test2.txt и попробовать прочитать test3.txt то увидим ошибку, так как ссылка не найдет файл на который она ссылается.
Жесткие ссылки в Linux имеют свои ограничения, их можно:
- создавать только для файлов, а для каталогов нельзя;
- использовать только в пределах одной файловой системы.
При удалении жёстких ссылок, физически файл удаляется (точнее его inode удаляется) только тогда, когда все жесткие ссылки идущие на этот inode удаляются.
Особенность символьных ссылок:
- удаление ссылки не приведет к удалению файла на который она ссылается;
- их можно создавать на объекты других файловых систем;
- их можно создавать и на файлы и на каталоги.
Практика
Все примеры я проведу на Debian 11, но в Ubuntu 22.04 всё происходит аналогично.
Для работы создадим один каталог, а в нем один файл:
alex@deb:~$ mkdir dir1 alex@deb:~$ touch dir1/file1.txt alex@deb:~$ ls -R .: dir1 ./dir1: file1.txt
Для создания ссылок используется команда ln. Создадим жесткую ссылку на файл file1.txt в домашнем каталоге:
alex@deb:~$ ln dir1/file1.txt file2.txt
При этом вначале указывается объект на который будем ссылаться, а затем новое имя файла.
Запишем что-нибудь в этот файл:
alex@deb:~$ echo 12345 > file2.txt alex@deb:~$ cat file2.txt 12345
Теперь прочитаем файл dir1/file1.txt:
alex@deb:~$ cat dir1/file1.txt 12345
Как видим два файла ссылаются на один объект. При правке одного файла, правится и второй.
Теперь переместим file2 в dir1 и проверим что ничего не сломалось и это тот же самый файл:
alex@deb:~$ mv file2.txt dir1/ alex@deb:~$ ls dir1/ file1.txt file2.txt alex@deb:~$ cat dir1/file2.txt 12345 alex@deb:~$ cat dir1/file1.txt 12345
Теперь создадим символьную ссылку file3.txt на файл file2.txt, для этого нужно команде ln указать опцию -s:
alex@deb:~$ ln -s dir1/file2.txt file3.txt alex@deb:~$ cat file3.txt 12345
То что это символьная ссылка можно выяснить посмотрев вывод команды ls -l:
alex@deb:~$ ls -l итого 4 drwxr-xr-x 2 alex alex 4096 янв 12 11:40 dir1 lrwxrwxrwx 1 alex alex 14 янв 12 11:42 file3.txt -> dir1/file2.txt
Обратите внимание на самый первый символ (l), что означает что этот файл — символьная ссылка.
Также вывод показывает на что ссылается данный объект. В данном примере ссылка идет по относительному пути, то есть не начинается с корня (/). Про относительный и абсолютный пути я писал в этой статье.
Теперь давайте переместим ссылку file3.txt в каталог dir1 и посмотрим что произойдет:
alex@deb:~$ mv file3.txt dir1/ alex@deb:~$ ls -l dir1/ итого 8 -rw-r--r-- 2 alex alex 6 янв 12 11:38 file1.txt -rw-r--r-- 2 alex alex 6 янв 12 11:38 file2.txt lrwxrwxrwx 1 alex alex 14 янв 12 11:42 file3.txt -> dir1/file2.txt alex@deb:~$ cat dir1/file3.txt cat: dir1/file3.txt: Нет такого файла или каталога
Так как путь ссылки не изменился, а файл ищется по относительному пути dir1/file2.txt, а в каталоге dir1 нет каталога dir1, то мы получили ошибку при попытке прочитать данный файл. Такие ссылки, которые ведут на объект которого нет, называются битыми ссылками.
Следует иметь ввиду, если вы создаете символьную ссылку с относительным путем, то подразумевается что ссылку в дальнейшим не будут перемещать из её каталога.
Если бы мы использовали абсолютный путь при создании ссылки, например так:
alex@deb:~$ ln -s /home/alex/dir1/file2.txt file3.txt alex@deb:~$ ls -l итого 4 drwxr-xr-x 2 alex alex 4096 янв 12 11:50 dir1 lrwxrwxrwx 1 alex alex 25 янв 12 11:59 file3.txt -> /home/alex/dir1/file2.txt
То такую ссылку можно перемещать. Но если переместить или удалить сам файл на который ссылается ссылка, то ссылка в любом случае станет битой.
Как распознать ссылки
То что файл является символьной ссылкой видно из вывода ls -l, это мы уже разбирали:
lrwxrwxrwx 1 alex alex 14 июл 18 16:44 file3.txt -> dir1/file2.txt
Но чтобы проверить битая ли это ссылка можно воспользоваться командой ls с опцией -L, которая попытается достучаться до всех файлов на которые есть символьные ссылки:
alex@deb:~$ ls -lL dir1/ ls: невозможно получить доступ к 'dir1/file3.txt': Нет такого файла или каталога итого 8 -rw-r--r-- 2 alex alex 6 янв 12 11:38 file1.txt -rw-r--r-- 2 alex alex 6 янв 12 11:38 file2.txt l. ? ? ? ? ? file3.txt
В выводе мы сразу заметим что файла dir1/file3.txt не существует, а ниже вопросики означают что file3.txt это битая ссылка.
Немного сложнее дело обстоит с жесткими ссылками. Давайте еще раз посмотрим на файлы file1.txt и file2.txt, которые ссылаются на один inode и являются жесткими ссылками друг для друга:
alex@deb:~$ ls -l dir1/ итого 8 -rw-r--r-- 2 alex alex 6 янв 12 11:38 file1.txt -rw-r--r-- 2 alex alex 6 янв 12 11:38 file2.txt lrwxrwxrwx 1 alex alex 14 янв 12 11:42 file3.txt -> dir1/file2.txt
Обратите внимание на двоечки после -rw-r—r— , это число жестких ссылок. Тут мы можем понять что file1.txt ссылается на объект у которого две жесткие ссылки, и тоже самое про file2.txt. Но то что это жесткие ссылки одного и того же объекта еще не понятно.
У ls есть опция -i, которая дополнительно выводит номер inode:
alex@deb:~$ ls -li dir1/ итого 8 783380 -rw-r--r-- 2 alex alex 6 янв 12 11:38 file1.txt 783380 -rw-r--r-- 2 alex alex 6 янв 12 11:38 file2.txt 783384 lrwxrwxrwx 1 alex alex 14 янв 12 11:42 file3.txt -> dir1/file2.txt
Как видно file1.txt и file2.txt ссылаются на один inode, под номером 783380. Значит это жесткие ссылки для одного и того же объекта.
В конце удалим все что мы создали:
alex@deb:~$ rm -rf file3.txt dir1/