Linux поиск по содержимому файлов

Обновлено: 07.07.2024

Утилита find представляет универсальный и функциональный способ для поиска в Linux. Данная статья является шпаргалкой с описанием и примерами ее использования.

Общий синтаксис

find <где искать> <опции>

<где искать> — путь к корневому каталогу, откуда начинать поиск. Например, find /home/user — искать в соответствующем каталоге. Для текущего каталога нужно использовать точку «.».

<опции> — набор правил, по которым выполнять поиск.

* по умолчанию, поиск рекурсивный. Для поиска в конкретном каталоге можно использовать опцию maxdepth.

Описание опций

Тип объекта поиска. Возможные варианты:

  • f — файл;
  • d — каталог;
  • l — ссылка;
  • p — pipe;
  • s — сокет.

Также доступны логические операторы:

Оператор Описание
-a Логическое И. Объединяем несколько критериев поиска.
-o Логическое ИЛИ. Позволяем команде find выполнить поиск на основе одного из критериев поиска.
-not или ! Логическое НЕ. Инвертирует критерий поиска.

Полный набор актуальных опций можно получить командой man find.

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

Поиск файла по имени

1. Простой поиск по имени:

* в данном примере будет выполнен поиск файла с именем file.txt по всей файловой системе, начинающейся с корня /.

2. Поиск файла по части имени:

* данной командой будет выполнен поиск всех папок или файлов в корневой директории /, заканчивающихся на .tmp

3. Несколько условий.

а) Логическое И. Например, файлы, которые начинаются на sess_ и заканчиваются на cd:

б) Логическое ИЛИ. Например, файлы, которые начинаются на sess_ или заканчиваются на cd:

в) Более компактный вид имеют регулярные выражения, например:

* где в первом поиске применяется выражение, аналогичное примеру а), а во втором — б).

4. Найти все файлы, кроме .log:

* в данном примере мы воспользовались логическим оператором !.

Поиск по дате

1. Поиск файлов, которые менялись определенное количество дней назад:

find . -type f -mtime +60

* данная команда найдет файлы, которые менялись более 60 дней назад.

2. Поиск файлов с помощью newer. Данная опция доступна с версии 4.3.3 (посмотреть можно командой find --version).

а) дате изменения:

find . -type f -newermt "2019-11-02 00:00"

* покажет все файлы, которые менялись, начиная с 02.11.2019 00:00.

find . -type f -newermt 2019-10-31 ! -newermt 2019-11-02

* найдет все файлы, которые менялись в промежутке между 31.10.2019 и 01.11.2019 (включительно).

б) дате обращения:

find . -type f -newerat 2019-10-08

* все файлы, к которым обращались с 08.10.2019.

find . -type f -newerat 2019-10-01 ! -newerat 2019-11-01

* все файлы, к которым обращались в октябре.

в) дате создания:

find . -type f -newerct 2019-09-07

* все файлы, созданные с 07 сентября 2019 года.

find . -type f -newerct 2019-09-07 ! -newerct "2019-09-09 07:50:00"

* файлы, созданные с 07.09.2019 00:00:00 по 09.09.2019 07:50

По типу

Искать в текущей директории и всех ее подпапках только файлы:

* f — искать только файлы.

Поиск по правам доступа

1. Ищем все справами на чтение и запись:

find / -perm 0666

2. Находим файлы, доступ к которым имеет только владелец:

find / -perm 0600

Поиск файла по содержимому

find / -type f -exec grep -i -H "content" <> \;

* в данном примере выполнен рекурсивный поиск всех файлов в директории / и выведен список тех, в которых содержится строка content.

С сортировкой по дате модификации

* команда найдет все файлы в каталоге /data, добавит к имени дату модификации и отсортирует данные по имени. В итоге получаем, что файлы будут идти в порядке их изменения.

Лимит на количество выводимых результатов

Самый распространенный пример — вывести один файл, который последний раз был модифицирован. Берем пример с сортировкой и добавляем следующее:

Поиск с действием (exec)

1. Найти только файлы, которые начинаются на sess_ и удалить их:

find . -name "sess_*" -type f -print -exec rm <> \;

* -print использовать не обязательно, но он покажет все, что будет удаляться, поэтому данную опцию удобно использовать, когда команда выполняется вручную.

2. Переименовать найденные файлы:

find . -name "sess_*" -type f -exec mv <> new_name \;

3. Вывести на экран количество найденных файлов и папок, которые заканчиваются на .tmp:

find . -name "*.tmp" | wc -l

4. Изменить права:

find /home/user/* -type d -exec chmod 2700 <> \;

* в данном примере мы ищем все каталоги (type d) в директории /home/user и ставим для них права 2700.

5. Передать найденные файлы конвееру (pipe):

* в данном примере мы использовали find для поиска строки test в файлах, которые находятся в каталоге /etc, и название которых заканчивается на .conf. Для этого мы передали список найденных файлов команде grep, которая уже и выполнила поиск по содержимому данных файлов.

6. Произвести замену в файлах с помощью команды sed:

find /opt/project -type f -exec sed -i -e "s/test/production/g" <> \;

* находим все файлы в каталоге /opt/project и меняем их содержимое с test на production.

Чистка по расписанию

Команду find удобно использовать для автоматического удаления устаревших файлов.

Открываем на редактирование задания cron:

0 0 * * * /bin/find /tmp -mtime +14 -exec rm <> \;

* в данном примере мы удаляем все файлы и папки из каталога /tmp, которые старше 14 дней. Задание запускается каждый день в 00:00.
* полный путь к исполняемому файлу find смотрим командой which find — в разных UNIX системах он может располагаться в разных местах.

Необходимо в каталоге найти файлы содержащие определенную фразу. Как это сделать? Думаю, многие не раз сталкивались с подобной проблемой, как необходимость найти в папке с файлами (а порой и подпапками, в которых тоже хорошо бы поискать) файл, зная кусочек его текста (ну, или догадываясь о нем). Я тоже много раз спотыкался об эту нужда и вот, наконец, собрался и написал небольшой скрипт на bash, выполняющий эту задачу. Не самой общераспространенной задачей, но всё же имеющей место быть, является поиск исполняемого файла программы. Она воспринимает в качестве параметра имя программы, а после выполнения выводит в терминал список с расположением одновременных файлов. Иногда может понадобится найти файл, в котором содержится определённая строчка или найти строку в файле, где есть нужное слово. В Linux всё это делается с помощью одной весьма простой, но в то же время мощной утилиты grep. С её помощью можно искать не только строчки в файлах, но и фильтровать вывод команд, и много чего ещё.

Linux поиск по содержимому файлов командой grep

Часто возникают ситуации, что нужно найти какой-нибудь текст, но вы не помните, в каком файле/файлах он содержится. Секрет популярности — её мощь, она отдает возможность пользователям сортировать и фильтровать текст на основе сложных правил.

Команда grep (расшифровывается как global regular expression print) — одна из самых востребованных команд в терминале Linux, которая входит в состав проекта GNU.

В этом варианте для поиска по содержимому файлов в каталоге можно использовать утилиту grep:

grep -r -n «text» /path

grep -r "Строчка для поиска"
grep -rl $'\xEF\xBB\xBF'

где:
-n показывает строку, где был найден фрагмент;
-r осуществляет розыск рекурсивно, в файлах в самом каталоге /path и в его подкаталогах;

Также можно приплюсовать опцию -C 3, чтобы видеть +- 3 строки вокруг (выше и ниже от найденной).

Дабы найти файл по его содержимому во всех Linux — подобных ОС, достаточно использовать утилиту find.

Linux поиск по содержимому файлов командой find

Своего рода швейцарским ножом в розыске файлов является команда find. Отметим, что она имеет множество опций, которые смогут кардинально изменять механизм поиска. Мы изложим лишь основные принципы, а с остальными способностями ознакомьтесь в справке по команде. Базовый принцип использования find состоит в указании папки поиска и опций. Например, выражение «find

/ -name *.cpp» осуществит поиск файлов, имеющих продолжение «cpp» по всем каталогам, находящимся в личной директории пользователя.

/usr/bin/find /папка -type f -exec grep -H 'строчка для поиска' <> ;

find /var/www/ -name "file.conf"
find /var/www/ -name "*.conf"

С поддержкою опции -exec каждому файлу, предназначенному для установки соответствия, можно добавить случайную обработку. Таким образом, появляется возможность осуществления поиска, как по имени файла, так и по охватываемому. Ниже приводится пример комбинирования команды find и grep за счет использования функции -exec.

/ -name *.cpp -user 'my-username' -group 'my-group'
find

/ -name '*.config' -type f -exec grep 'user' <> \;
find /home/ ( -name "*.php" -or -name "*.html" -or -name "*.js" )
-exec grep -lHEi $'\xEF\xBB\xBF' <> ;

А возможно и еще проще

Linux поиск по содержимому файлов командой which

Бригада which ищет только те файлы, у которых есть право на выполнение как программы. Розыск осуществляется по директориям, заданным в переменной окружения PATH. Содержимое переменной PATH сможет отличаться для различных пользователей. Чтобы охватить как можно большее количество системных директория, необходимо войти в систему под учетной записью администратора.

which cat
/bin/cat
which docker-stack
/home/username/.local/bin/docker-stack

Linux поиск по содержимому файлов командой locate

Поиск, производимый командой locate весьма быстр. Однако учитывайте тот факт, что системная база данных может быть не живой на момент осуществления операции. Механизм сканирования файловой системы, время его проведения и вобщем наличие такого инструмента может разниться в различных дистрибутивах Linux. Команда locate может быть полезна лишь при поиске файла по его имени. Однако для проверки текстового содержимого документов на вступление искомых данных нужно использовать другой инструмент.

Команда locate представляется альтернативой для find.

Данная команда, как правило, работает быстрее и может с легкостью производить поиск (в широком смысле — стремление добиться чего-либо, найти что-либо; действия субъекта, направленные на получение нового или утерянного (забытого): новой информации (поиск информации), данных,) по всей файловой системы. Linux имеет специальную команду grep, какая принимает шаблон для поиска и имя файла (именованная область данных на носителе информации). В случае нахождения совпадений, они будут выведены в терминал. В всеобщем виде выражение можно составить как «grep шаблон_поиска имя_файла». Чтобы отыскать файлы с помощью команды locate, просто используйте следующий синтаксис:

К образцу, чтобы возвращать только файлы, содержащие сам запрос, вместо того чтобы вводить каждый файл, который содержит запрос в ведущих к нему каталогах, можно утилизировать флаг –b (чтоб искать только basename, базовое имя файла):

Команды find и locate – отличные инструменты для поиска файлов в UNIX‐подобных операционных системах. Любая из этих утилит имеет свои преимущества. Мы рассмотрели использование команд для поиска и фильтрации вывода бригад в операционной системе Linux. При правильном применении эта утилита станет мощным инструментом в ваших руках. Несмотря на то, что команды find и locate сами по себе очень мощны, их действие возможно расширить, комбинируя их с другими командами. Научившись работать с find и locate, попробуйте чистить их результаты при помощи команд wc, sort и grep.

Иногда бывают ситуации, когда нужно просканировать всю файловую систему Linux и найти все файлы, содержащие определённую строку текста. То есть нужно выполнить поиск не по имени файла, а по содержимому текстового файла.

Пример таких ситуаций из практики:

Пример — поиск заголовка Strict-Transport-Security в директории конфигурационных файлов веб-сервера:


Одним из лучших вариантов поиска всех файлов, содержащих заданный текст, является команда:

В этой команде используются следующие опции:

-r (также можно использовать -R) для рекурсивного поиска — то есть поиск будет выполнен в папке и подпапках. Опция -R делает так, что программа следует по символическим ссылкам, если натыкается на них, соответственно, с опцией -r этого не происходит. Но поиск является рекурсивным в обоих случаях

-n означает выводить номера строку (чтобы быстрее найти в них нужное место)

-w используется для поиска по полным словам. При использовании опции -w будут выбраны только строки, которые содержат совпадения целых слов. То есть для того, чтобы совпадение засчиталось, совпавшая подстрока быть либо вначале строки, либо перед ней должен идти несловесный составной символ. Аналогично она должна быть либо в конце строки, либо за ней должен следовать несловесный составной символ. Словесными составными символами являются буквы, цифры и подчёркивание. Соответственно, несловесными являются все остальные: пробелы, знаки препинания, дефисы и прочее.

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

Рассмотрим ещё несколько опций, которые могут оказаться весьма полезными:

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

-l (маленькая L) подавляет нормальный вывод; вместо него выводится имя каждого файла, в котором найдено совпадение. То есть по умолчанию выводиться совпавшая строка, а с этой опцией будут выводиться только имена файлов, в которых найдена строка. Сканирование будет остановлено после первого совпадения.

--color[=КОГДА], --colour[=КОГДА] — используется для подсветки в терминале совпавшей подстроки, контекстных строк, имён файлов, номеров строк, байтового смещения и разделителей (для полей и групп контестных строк). КОГДА можно указывать или не указывать по жоеланию. В качестве КОГДА может быть never (никогда), always (всегда) или auto (автоматически).

-I — пропускать бинарные файлы. При рекурсивной обработке могут попадаться не текстовые файлы, натыкаясь на которые grep будет показывать предупреждения. Эта опция делает обработку бинарных файлов такой, как если бы они не содержали совпадающих данных.

В качестве шаблона grep используются регулярные выражения — они являются крайне мощным инструментом для поиска строк. Тем не менее, если вы не умеете пользоваться регулярными выражениями, то вы можете получить не те результаты, которых ожидаете, поскольку некоторые символы в регулярных выражениях имеют специальное значение. По этой причине рекомендуется ознакомиться с большой понятной инструкцией «Регулярные выражения и команда grep».

Ещё один вариант — использовать опцию -F. Она будет интерпретировать ШАБЛОНЫ как фиксированные строки, а не как регулярные выражения. С одной стороны, команда grep потеряет часть своей гибкости, но при этом вы получите более предсказуемый результат, если вы не понимаете регулярные выражения.

В зависимости от обстоятельств, можно использовать для повышения эффективности поиска следующие флаги:

--exclude=GLOB — означает пропустить файлы, с именем суффикса, которое совпадёт с шаблоном GLOB. Имя суффикса это как полное имя, так и любой суффикс, начинающийся после / и перед не-/ (то есть между слэшей в пути имени файла). При рекурсивном поиске, пропускаются все подфайлы, чьё базовое имя совпадает с GLOB. Базовое имя — это часть после последнего слэша (/). Шаблон GLOB поддерживает несколько подстановочных символов. Шаблон (GLOB) может использовать в качестве подстановочных символов * (означает последовательность нуля или более символов), ? (означает ровно один символ), и [СИМВОЛЫ] (означает любой один из СИМВОЛОВ), (означает любой из символов), а также \ для экранирования подстановочных символов или символа обратного слэша, чтобы они начали восприниматься буквально.

--include=GLOB — искать только файлы, чьё базовое имя совпадает с GLOB (можно использовать подстановочные символы, как описано чуть выше)

--exclude-dir=GLOB — пропустить директории с суффиксом имени, которые совпадает с шаблоном GLOB. При рекурсивном поиски, пропуск любых поддиректорий, чьё базовое имя совпадает с GLOB. Любые избыточные конечные слэши в GLOB игнорируются.

Чтобы было понятнее, рассмотрим примеры. Допустим мы хотим выполнить поиск только по файлам с расширениями .c или .h:

В этой команде * (звёздочка) означает любое имя файла. Но эта звёздочка экранирована, поскольку для терминала она также имеет особое значение. В этом имене должна идти точка и буква c или h.

Следующий поиск исключит из результатов все файлы, которые заканчиваются на расширение .o:

Для директорий возможно исключить конкретную директорию(ии) через параметр --exclude-dir. Например, следующая команда исключит dirs dir1/, dir2/ и все другие директории соответствующие *.dst/:

Команда Grep в Linux (Поиск текста в файлах)

Команда grep означает «глобальная печать регулярных выражений», и это одна из самых мощных и часто используемых команд в Linux.

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

grep Синтаксис команды

Синтаксис grep команды следующий:

Элементы в квадратных скобках не являются обязательными.
  • OPTIONS - Ноль или более вариантов. Grep включает в себя ряд параметров, которые контролируют его поведение.
  • PATTERN - Шаблон поиска.
  • FILE - Ноль или более имен входных файлов.

Чтобы иметь возможность искать файл, пользователь, выполняющий команду, должен иметь доступ на чтение к файлу.


Поиск строки в файлах

Основное использование grep команды - поиск строки (текста) в файле.

Например, чтобы отобразить все строки, содержащие строку bash из /etc/passwd файла, вы должны выполнить следующую команду:


Вывод должен выглядеть примерно так:

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


Инвертировать (исключить) совпадение

Чтобы отобразить линии, которые не соответствуют шаблону, используйте параметр -v (или --invert-match ).

Например, чтобы напечатать строки, которые не содержат строку, которую nologin вы используете:

Использование Grep для фильтрации выходных данных команды

Выходные данные команды могут быть отфильтрованы с grep помощью сквозного трубопровода, и только те строки, которые соответствуют заданному шаблону, будут напечатаны на терминале.

Например, чтобы узнать, какие процессы выполняются в вашей системе как пользователь, www-data вы можете использовать следующую ps команду:


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

Рекурсивный поиск

Для рекурсивного поиска шаблона, grep используйте -r опцию (или --recursive ). Когда эта опция используется, grep будет выполняться поиск по всем файлам в указанном каталоге, пропуская символические ссылки, которые встречаются рекурсивно.

Чтобы перейти по всем символическим ссылкам , вместо этого -r используйте -R опцию (или --dereference-recursive ).

Вот пример, показывающий, как искать строку baks.dev во всех файлах в /etc каталоге:


Вывод будет включать совпадающие строки с префиксом полного пути к файлу:

Если вы используете -R опцию, grep перейдите по всем символическим ссылкам:

Обратите внимание на последнюю строку вывода ниже. Эта строка не печатается, когда grep вызывается -r из-за того, что файлы в sites-enabled каталоге Nginx являются символическими ссылками на файлы конфигурации внутри sites-available каталога.

Показывать только имя файла

Чтобы подавить grep вывод по умолчанию и печатать только имена файлов, содержащих сопоставленный шаблон, используйте параметр -l (или --files-with-matches ).

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


Вывод будет выглядеть примерно так:

-l Вариант обычно используется в сочетании с рекурсивной опции -R :


Поиск без учета регистра

По умолчанию учитывается grep регистр. Это означает, что прописные и строчные символы рассматриваются как разные.

Чтобы игнорировать регистр при поиске, grep используйте -i опцию (или --ignore-case ).

Например, при поиске Zebra без какой-либо опции следующая команда не будет отображать никаких выходных данных, т.е. есть совпадающие строки:


Но если вы выполните поиск без учета регистра, используя -i опцию, он будет соответствовать как заглавным, так и строчным буквам:


Указание «Зебра» будет соответствовать «Зебра», «ZEbrA» или любой другой комбинации прописных и строчных букв для этой строки.

Поиск полных слов

При поиске строки grep будут отображаться все строки, в которых строка встроена в более крупные строки.

Например, если вы ищете «gnu», все строки, где «gnu» встроен в более крупные слова, такие как «cygnus» или «magnum», будут совпадать:

Чтобы вернуть только те строки, в которых указанная строка представляет собой целое слово (заключенное не в словах), используйте параметр -w (или --word-regexp ).

Символов слова включают в себя буквенно - цифровые символы ( a-z , A-Z и 0-9 ) и подчеркивание ( _ ). Все остальные символы рассматриваются как несловесные символы.

Если вы выполните ту же команду, что и выше, включая -w опцию, grep команда вернет только те строки, которые gnu включены в качестве отдельного слова.

Показать номера строк

Опция -n (или --line-number ) указывает grep показывать номер строки, содержащей строку, которая соответствует шаблону. Когда эта опция используется, grep печатает совпадения на стандартный вывод с префиксом номера строки.

Например, чтобы отобразить строки из /etc/services файла, содержащего строку с bash префиксом с соответствующим номером строки, вы можете использовать следующую команду:


Вывод ниже показывает нам, что совпадения находятся в строках 10423 и 10424.

Количество совпадений

Чтобы напечатать количество совпадающих строк в стандартный вывод, используйте параметр -c (или --count ).

В приведенном ниже примере мы подсчитываем количество учетных записей, которые имеют /usr/bin/zsh оболочку.


Скрытый режим

-q (Или --quiet ) говорит , grep чтобы работать в скрытом режиме , чтобы не показывать ничего на стандартный вывод. Если совпадение найдено, команда завершается со статусом 0 . Это полезно при использовании grep в сценариях оболочки, где вы хотите проверить, содержит ли файл строку, и выполнить определенное действие в зависимости от результата.

Вот пример использования grep в тихом режиме в качестве команды тестирования в if инструкции :


Основное регулярное выражение

GNU Grep имеет три набора функций регулярных выражений : базовый, расширенный и Perl-совместимый.

По умолчанию grep шаблон интерпретируется как базовое регулярное выражение, где все символы, кроме метасимволов, на самом деле являются регулярными выражениями, которые соответствуют друг другу.

Ниже приведен список наиболее часто используемых метасимволов:

Используйте ^ символ (каретка), чтобы соответствовать выражению в начале строки. В следующем примере строка kangaroo будет соответствовать только в том случае, если она встречается в самом начале строки.

Используйте $ символ (доллар), чтобы соответствовать выражению в конце строки. В следующем примере строка kangaroo будет соответствовать только в том случае, если она встречается в самом конце строки.

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

Используйте [ ] (скобки) для соответствия любому отдельному символу, заключенному в скобки. Например, найдите строки, содержащие accept или « accent , вы можете использовать следующий шаблон:

Используется [^ ] для соответствия любому отдельному символу, не заключенному в скобки. Следующий шаблон будет соответствовать любой комбинации строк, содержащих co(any_letter_except_l)a , например coca , cobalt и так далее, но не будет совпадать со строками, содержащими cola ,


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

Расширенные регулярные выражения

Чтобы интерпретировать шаблон как расширенное регулярное выражение, используйте параметр -E (или --extended-regexp ). Расширенные регулярные выражения включают в себя все основные метасимволы, а также дополнительные метасимволы для создания более сложных и мощных шаблонов поиска. Ниже приведены некоторые примеры:

Сопоставьте и извлеките все адреса электронной почты из данного файла:

Сопоставьте и извлеките все действительные IP-адреса из данного файла:

-o Опция используется для печати только строку соответствия.

Поиск по шаблону нескольких строк

Два или более шаблонов поиска могут быть объединены с помощью оператора ИЛИ | .

По умолчанию grep шаблон интерпретируется как базовое регулярное выражение, в котором метасимволы, такие как | теряют свое особое значение, и их версии с обратной косой чертой должны использоваться.

В приведенном ниже примере мы ищем все вхождения слов fatal , error и critical в журнале Nginx файл ошибки:


Если вы используете опцию расширенного регулярного выражения -E , оператор | не должен быть экранирован, как показано ниже:


Печать строк перед сопоставлением

Чтобы напечатать определенное количество строк перед сопоставлением строк, используйте параметр -B (или --before-context ).

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


Печать строк после сопоставления

Чтобы напечатать определенное количество строк после сопоставления строк, используйте параметр -A (или --after-context ).

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


Вывод

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

Читайте также: