- PVSM.RU - https://www.pvsm.ru -
База данных — это сердце многих приложений, от полнофункциональных корпоративных сайтов до сравнительно простых инструментов, например, для ведения списков покупок и финансовых трекеров. Популярны реляционные базы данных на основе SQL, но в Linux можно собрать более простую и прозрачную альтернативную базу данных.
В Linux доминируют текстовые файлы. В Linux есть экосистема и множество надёжных инструментов, при помощи которых текстовые файлы удобно сцеплять — и очень многого добиться, оперируя такими файлами.
В частности, можно собрать базу данных, то есть структурированный источник информации, который может пригодиться вам для очень многих вещей. Работая с текстовыми файлами и инструментами командной строки, можно создавать простые прототипы, быстро проверять ваши данные, а также версионировать данные столь же легко, как и любой код.
В Linux есть много полезных команд [1], в том числе для работы с текстом. Многие из этих команд действуют как фильтры, получающие данные через стандартный ввод, выполняющие над этими данными некоторые операции и выдающие стандартный вывод.
grep обеспечивает поиск по вводимой информации и позволяет выбрать те строки, которые соответствуют одному или нескольким шаблонам.
cut извлекает избранные фрагменты каждой строки и записывает их в стандартный вывод.
awk — более мощный язык для сканирования и обработки паттернов.
sort выполняет именно сортировку (как и следовало ожидать), но может сортировать данные и по конкретным столбцам, а также корректно справляется с числовой/алфавитной сортировкой.
При помощи команд head и tail можно извлекать из вывода заданный срез строк.
join поддерживает взаимосвязанные данные, расположенные во множестве файлов.
В данном примере мы создадим простую базу данных для приложения из разряда «список дел». Весь базовый функционал такого приложения можно реализовать при помощи стандартных инструментов Linux. В дальнейшем возможности этого приложения можно будет расширить при помощи скриптового языка, либо перенеся его на реляционную базу данных.
Создание таблиц в виде двумерных файлов
Один из простейших структурированных текстовых форматов называется DSV или значения, разделённые разделителем [2]. Это более общий случай формата CSV —значений, разделённых запятыми. В структурированных текстовых файлах под Linux в качестве разделителя полей часто используются пробел или двоеточие. Классический пример — файл /etc/passwd
:
В таком формате можно хранить разнообразные данные, в том числе и список дел:
Buy milk:2024-10-21:2:open
Call bank:2024-10-20:1:closed
Для обновления базы данных подойдёт любой текстовый редактор [3] — в этом заключается ещё одно достоинство обычного текста. Можно добавлять элементы непосредственно из командной строки, перенаправляя вывод из echo в файл [4]:
echo "Take out the trash:$(date -I):3:open" > tasks
Вот эквивалентный код на SQL:
INSERT INTO tasks VALUES('Take out the trash', CURDATE(), '3', 'open')
Обратите внимание: для получения актуальной даты в этой команде используется подкоманда. Немного неудобно прописывать её руками, значительно удобнее было бы автоматизировать её при помощи скрипта.
Выбор данных — пожалуй, самая типичная задача при работе с базой данных. Самый простой вариант — выбрать из таблицы всю информацию, то есть
SELECT * FROM tasks
Такой командой мы извлекаем все столбцы базы данных на высоту всех строк. Если мы имеем дело с файловой базой данных, то эквивалентная команда также тривиальна:
cat tasks
Чуть более искусная операция — сузить выборку до конкретных столбцов. Вот как это делается в SQL:
SELECT task FROM tasks
При помощи инструмента cut можно реализовать практически тот же самый функционал:
cut -d':' -f1 tasks
При помощи опции d
задаём разделитель — тот знак, который будет ставиться между полями в каждой строке вашего файла. При помощи опции f
выбираем конкретные поля. Следующий корд позволяет вывести список всех задач, содержащихся в вашей базе данных:
Обычно требуется вытащить из базы данных не все строки, а как-то ограничить результаты. В таких случаях наиболее распространено требование отфильтровать содержимое по значениям, как, например, здесь:
SELECT * FROM tasks WHERE status=open
В данном случае grep отлично нам подойдёт. Воспользовавшись этой командой, можно сравнивать строки с шаблоном, заданным в виде регулярного выражения. Таким образом можно найти, например, все задачи, имеющие статус "open" (открыта):
grep 'open$' tasks
В данном случае мы опираемся на тот факт, что каждая строка оканчивается полем «status»; знак $ — это конец строки. Что касается полей в середине строки, для их обработки может потребоваться более сложное регулярное выражение. Например, вот как можно получить все строки с приоритетом 2:
grep ':2:[^:]*$' tasks
Но grep обеспечивает сопоставление только с текстовыми шаблонами и не справляется с более сложными выражениями, например, с такими:
SELECT status, task FROM tasks WHERE date<2024-10-21
В этом коде SQL при помощи логического сравнения мы получаем задачи, заведённые до определённой даты. Можно попытаться собрать более сложное регулярное выражение, но так мы рискуем выйти за рамки возможностей grep.
В данном случае вам потребуется более сложный инструмент, такой как awk:
awk -F':' '$2<"2024-10-21" {print $1 ":" $2 }' tasks
Awk может справиться одновременно с задачами grep и cut. В данном примере часть
$2<"2024-10-21"
— это предусловие, означающее, что шаблону соответствуют лишь значения с более ранней датой. После этого команда выведет на экран первые два столбца из каждой строки.
В языке SQL предусмотрен оператор LIMIT
, при помощи которого можно выбирать конкретное количество элементов из результатов. Вот как выбрать первые две строки:
head -2 tasks
При помощи tail
можно получить n последних строк. В совокупности с head
мы воспроизводим функционал оператора LIMIT
, причём включая сдвиги. Например, вот как получить строки 2-3:
head -3 tasks | tail -2
Во многих SQL-командах важная роль отводится оператору ORDER BY
. К счастью, в Linux есть отличная эквивалентная команда sort
. Подобно cut
и awk
, можно указать разделительный знак и поле по номеру, хотя флагам соответствуют разные буквы. На этот раз t
— это разделитель, а k
— номер поля:
sort -t':' -k2 tasks
Далее будут отображены все поля, отсортированные по дате:
Суть реляционных баз данных заключается в описании отношений между различными таблицами, где поле из одной ссылается на поле из другой. Возможно, вы раньше не знали, что в Linux есть команда, эквивалентная оператору JOIN
из языка SQL — неудивительно, что называется она join
.
Давайте расширим данные списка дел так, чтобы в нём можно было учитывать задачи для нескольких пользователей. Для начала добавим в исходный файл задач новый столбец name так, чтобы данные приняли следующий вид:
Затем создадим файл people, в котором будем хранить данные по каждой персоне, чьи задачи мы учитываем:
Теперь можно воспользоваться командой join
с разделителем, который указывается через опцию t
:
join -t':' -1 5 -2 1 tasks people
При помощи опций -1 и -2 указываем номера тех полей из каждого файла, которые мы собираемся объединять. Здесь речь идёт о первом и пятом полях соответственно. Команда join
будет использовать первое поле по умолчанию, так что код можно упростить до:
join -t':' -1 5 tasks people
В результате получим:
Чтобы сделать вывод немного чище, можно конвейеризовать объединённые таблицы. В таком случае получится обрезать и опустить поле name
:
join -t':' -1 5 tasks people | cut -d':' -f2-
Кроме того, можно будет объединить два имени в одно при помощи awk
:
join -t':' -1 5 tasks people | awk -F':' '{print $2":"$3":"$4":"$5":"$6" "$7}'
В заключение давайте рассмотрим гораздо более сложное выражение на языке SQL. Вот выражение, при помощи которого мы объединяем обе таблицы, чтобы получить имена, а также выбрать конкретные столбцы и выбрать строки с определённым приоритетом. Далее выполняется сортировка по дате и выбирается только первая подходящая строка:
SELECT task,date,priority,status,first_name,last_name
FROM tasks t
LEFT JOIN people p ON t.name=p.name
WHERE priority=2
ORDER BY date
LIMIT 1
Эквивалентный конвейер команд, пожалуй, несколько сложнее понять, но и в этом нет ничего трудного, если вы знакомы со следующими ключевыми инструментами:
join -t':' -1 5 -2 1 tasks people
| awk -F':' '{print $2":"$3":"$4":"$5":"$6" "$7}'
| grep ':2:'
| sort -t ':' -k2
| head -1
Автор: Sivchenko_translate
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/linux/402205
Ссылки в тексте:
[1] много полезных команд: https://www.howtogeek.com/412055/37-important-linux-commands-you-should-know/
[2] DSV или значения, разделённые разделителем: https://en.wikipedia.org/wiki/Delimiter-separated_values
[3] любой текстовый редактор: https://www.howtogeek.com/trey-these-linux-text-editors/
[4] перенаправляя вывод из echo в файл: https://www.howtogeek.com/299219/how-to-save-the-output-of-a-command-to-a-file-in-bash-aka-the-linux-and-macos-terminal/
[5] Источник: https://habr.com/ru/articles/857756/?utm_source=habrahabr&utm_medium=rss&utm_campaign=857756
Нажмите здесь для печати.