База данных — это сердце многих приложений, от полнофункциональных корпоративных сайтов до сравнительно простых инструментов, например, для ведения списков покупок и финансовых трекеров. Популярны реляционные базы данных на основе SQL, но в Linux можно собрать более простую и прозрачную альтернативную базу данных.
Базу данных какого рода можно собрать в Linux
В Linux доминируют текстовые файлы. В Linux есть экосистема и множество надёжных инструментов, при помощи которых текстовые файлы удобно сцеплять — и очень многого добиться, оперируя такими файлами.
В частности, можно собрать базу данных, то есть структурированный источник информации, который может пригодиться вам для очень многих вещей. Работая с текстовыми файлами и инструментами командной строки, можно создавать простые прототипы, быстро проверять ваши данные, а также версионировать данные столь же легко, как и любой код.
Какими инструментами можно воспользоваться?
В Linux есть много полезных команд, в том числе для работы с текстом. Многие из этих команд действуют как фильтры, получающие данные через стандартный ввод, выполняющие над этими данными некоторые операции и выдающие стандартный вывод.
-
grep обеспечивает поиск по вводимой информации и позволяет выбрать те строки, которые соответствуют одному или нескольким шаблонам.
-
cut извлекает избранные фрагменты каждой строки и записывает их в стандартный вывод.
-
awk — более мощный язык для сканирования и обработки паттернов.
-
sort выполняет именно сортировку (как и следовало ожидать), но может сортировать данные и по конкретным столбцам, а также корректно справляется с числовой/алфавитной сортировкой.
-
При помощи команд head и tail можно извлекать из вывода заданный срез строк.
-
join поддерживает взаимосвязанные данные, расположенные во множестве файлов.
У вас есть инструментарий Linux — как с его помощью создать и использовать базу данных
В данном примере мы создадим простую базу данных для приложения из разряда «список дел». Весь базовый функционал такого приложения можно реализовать при помощи стандартных инструментов Linux. В дальнейшем возможности этого приложения можно будет расширить при помощи скриптового языка, либо перенеся его на реляционную базу данных.
Создание таблиц в виде двумерных файлов
Один из простейших структурированных текстовых форматов называется DSV или значения, разделённые разделителем. Это более общий случай формата CSV —значений, разделённых запятыми. В структурированных текстовых файлах под Linux в качестве разделителя полей часто используются пробел или двоеточие. Классический пример — файл /etc/passwd
:
В таком формате можно хранить разнообразные данные, в том числе и список дел:
Buy milk:2024-10-21:2:open
Call bank:2024-10-20:1:closed
Для обновления базы данных подойдёт любой текстовый редактор — в этом заключается ещё одно достоинство обычного текста. Можно добавлять элементы непосредственно из командной строки, перенаправляя вывод из echo в файл:
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
Выбор столбцов при помощи cut
Чуть более искусная операция — сузить выборку до конкретных столбцов. Вот как это делается в SQL:
SELECT task FROM tasks
При помощи инструмента cut можно реализовать практически тот же самый функционал:
cut -d':' -f1 tasks
При помощи опции d
задаём разделитель — тот знак, который будет ставиться между полями в каждой строке вашего файла. При помощи опции f
выбираем конкретные поля. Следующий корд позволяет вывести список всех задач, содержащихся в вашей базе данных:
Выбор строк при помощи grep или awk
Обычно требуется вытащить из базы данных не все строки, а как-то ограничить результаты. В таких случаях наиболее распространено требование отфильтровать содержимое по значениям, как, например, здесь:
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"
— это предусловие, означающее, что шаблону соответствуют лишь значения с более ранней датой. После этого команда выведет на экран первые два столбца из каждой строки.
Постраничное разбиение результатов при помощи head и tail
В языке SQL предусмотрен оператор LIMIT
, при помощи которого можно выбирать конкретное количество элементов из результатов. Вот как выбрать первые две строки:
head -2 tasks
При помощи tail
можно получить n последних строк. В совокупности с head
мы воспроизводим функционал оператора LIMIT
, причём включая сдвиги. Например, вот как получить строки 2-3:
head -3 tasks | tail -2
Сортировка строк при помощи sort
Во многих SQL-командах важная роль отводится оператору ORDER BY
. К счастью, в Linux есть отличная эквивалентная команда sort
. Подобно cut
и awk
, можно указать разделительный знак и поле по номеру, хотя флагам соответствуют разные буквы. На этот раз t
— это разделитель, а k
— номер поля:
sort -t':' -k2 tasks
Далее будут отображены все поля, отсортированные по дате:
Объединение таблиц при помощи join
Суть реляционных баз данных заключается в описании отношений между различными таблицами, где поле из одной ссылается на поле из другой. Возможно, вы раньше не знали, что в 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