284 подписчика

#50. Lite-версия программы Cat на Golang

Это статья об основах программирования на Go. На канале я рассказываю об опыте перехода в IT с нуля, структурирую информацию и делюсь мнением.

Хой, джедаи и амазонки!

Рассказываю, как написал программу-аналог утилиты Cat для Linux на Go. Будет теория - в ней расскажу, что это за программа, зачем она нужна. Затем примеры кода и личные наблюдения.

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

1. Чем полезна утилита Cat

Программа "cat" (сокращение от "concatenate") - утилита командной строки, широко используемую в операционных системах Linux. Она предназначена для чтения, объединения и вывода содержимого текстовых файлов в терминал или в другой файл.

Ниже пример работы с терминалом в Linux, где я использую команду cat, чтобы посмотреть содержимое файла first.txt, который содержит текст "контент первого файла".

Пример работы утилиты Cat
Пример работы утилиты Cat

"Cat" может быть полезной во множестве сценариев и ситуаций. Некоторые из основных случаев использования включают:

  1. Просмотр содержимого файла: можем использовать "cat" для просмотра содержимого текстового файла в терминале. Это полезно, когда нам нужно быстро посмотреть на содержимое файла без редактирования.
  2. Создание или объединение файлов: с помощью "cat" можно создавать новые файлы или объединять содержимое нескольких файлов в один. Например, команда "cat file1.txt file2.txt > merged.txt" объединит содержимое файлов "file1.txt" и "file2.txt", и результат будет сохранен в файле "merged.txt".
  3. Перенаправление вывода: "cat" позволяет перенаправлять вывод в другие программы или файлы. Мы можем использовать утилиту для передачи содержимого одного файла в другую программу для дальнейшей обработки данных.

Программа "cat" является частью проекта GNU Core Utilities и была впервые включена в дистрибутивы Linux в 1987 году (дату подсказала нейросетка, достоверных подтверждений не нашёл в источниках). С тех пор она стала одной из стандартных утилит, которая широко используется в командной строке Linux.

Лого пакета GNU Coreutils
Лого пакета GNU Coreutils

Версия cat в GNU Coreutils, т.е. пакета с различным ПО, была написана Торбьорном Гранлундом и Ричардом Столлманом (Torbjorn Granlund and Richard M. Stallman). Фото Торбьорна найти не удалось, а фото Ричарда см. ниже.

Ричард Столлман на LibrePlanet 2019, Википедия
Ричард Столлман на LibrePlanet 2019, Википедия

Использование "cat" может быть полезно для системных администраторов, разработчиков и любых пользователей Linux, которым нужно работать с текстовыми файлами в командной строке.

Подробнее об этой программе можно почитать, например, в этой статье на личном сайте веб-разработчика, который копает в направлении открытого ПО. Кстати, у него нет технического образования, но это не мешает ему быть крутым в своём деле.

2. Пишем lite-версию Cat на Go

2.1. Техническое задание

Моя задача сделать минимальный функционал cat. Что там будет:

  • В терминал следом за инициацией программы (условного go run main.go) вводим имя одного, двух или трёх файлов.
  • Первый и (если он есть) второй файл - те, которые нужно прочитать и вывести содержимое в терминал.
  • Если присутствует третий файл - в него нужно записать содержимое первых двух.

Фрагмент запуска кода может выглядеть так:

Ввод команды запуска кода с аргументами в терминал
Ввод команды запуска кода с аргументами в терминал

Здесь мы передаём три аргумента, т.е. три имени файла. Первые два мы прочитаем, а в третий запишем их содержимое.

Go разбираться как это делать.

2.2. Код

С кодом можно ознакомиться на моём GitHub'е. Я использовал для решения задачи os.Args, т.к. аргументы передаются в строгой последовательности, что делает os.Args наиболее уместным.

Далее немного теории об os.Args.

2.3. Об os.Args

Что такое os.Args - рассмотрим стандартную библиотеку:

Фрагмент стандартной библиотеки
Фрагмент стандартной библиотеки

Суть перевода примерно следующая:

Пакет os предоставляет независимый от платформы интерфейс для работы операционной системы.

Мало что понятно, если честно. Попробую посмотреть, какой тип данных у этой конструкции в IDE на-практике:

Код и вывод в терминал
Код и вывод в терминал

Ага, тип данных у переменной os.Args - это []string, т.е. срез строк, - как и указано в спецификации. Уже неплохо.

Библиотека os.Args в языке программирования Go предоставляет доступ к аргументам командной строки, переданным при запуске программы.

Переменная os.Args содержит все аргументы командной строки, включая имя самой программы (это важно). Первый элемент среза os.Args всегда является полным путем и именем запущенного исполняемого файла.

Мы можем использовать переменную os.Args для получения доступа к аргументам командной строки в программе. Например, если мы хотим получить доступ к первому аргументу после имени программы, вы можете обратиться к os.Args[1] - как с обычными массивами.

Итак, теорию по os.Args изучили, идём практиковаться.

2.4. Что интересного в коде

Расскажу о нескольких вещах, на которые стоит обратить внимание.

2.4.1. Функция подсчёта количества аргументов

Рассмотрим фрагмент кода:

Фрагмент кода №1
Фрагмент кода №1

1) В строке 19 я возвращаю ошибку (либо её отсутствие). Т.к. логично вернуть ошибку, чтобы вызываемая функция решила, что делать. Что именно делать - другой вопрос, в моей версии пока просто печатать информацию в терминал.

2) В строке 22 я проверяю, чтобы аргументов было минимум 2. Почему два, вы можете спросить. В ТЗ ведь было сказано, что можно принимать и один аргумент. А дело в том, что первым аргументом всегда будет полный путь исполняемого файла.

3) В строке 24 я использовал вложенные условия - это не очень хорошо. У меня был выбор сделать всё через switch, но в этом случае мне пришлось бы пилить одинаковые отдельные функции при наличии одного и двух аргументов, что не есть хорошо для чистого кода. По крайней мере со switch я видел такое развитие ситуации.

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

output := os.Stdout

или

output, err = os.OpenFile(fileNameOutput, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)

Затем вызывать функцию, передав туда срез из имен файлов которые нужно выводить и то куда выводить

err := printFiles(args, output)

Затем в цикле считать файлы и вывести.

Но как по мне - количество вложенных условий не страшное, поэтому пусть остаётся как есть.

2.4.2. Читаем файлы

Рассмотрим фрагмент кода:

Фрагмент кода №2
Фрагмент кода №2

1) В строке 39 я создаю переменную с типом срез байтов. Аналогично можно было бы сделать []uint8, т.к. при чтении файла в строке кода 41, сохранение происходит в такой тип переменной.

2) Далее я записываю в этот срез в строке 46 считанную информацию. Здесь была проблема сделать "энтер" между содержимым двух файлов. Пришлось городить такую конструкцию с двумя append'ами. Иначе было бы примерно такой вывод в терминал содержимого обоих файлов:

Контент первого файлаКонтент второго файла.

А с двумя append'ами получаем следующий вывод:

Контент первого файла
Контент второго файла.

3) Метод чтения из файла использовал самый простой. Способы работы с файлами я наглядно разбирал в этой публикации.

Ещё интересно в этом фрагменте кода то, что я читаю передаваемые аргументы (файлы) в цикле. Т.е. для меня неважно - один аргумент, два, или потенциально большее количество. Т.е. не читаю по-отдельности каждый файл, а перебираю. Это с одной стороны не усложняет код для понимания, и в то же время сокращает количество строк кода. Т.е. хорошее решение на мой взгляд для чистого кода.

2.4.3. Пишем в файл

Рассмотрим фрагмент кода:

Фрагмент кода №3
Фрагмент кода №3

В 52й строке я назначаю права доступа к файлу. Подробнее о правах доступа можно почитать в одной из моих предыдущих публикаций.

2.5. Итог разработки аналога Cat

Задача была простая, я её решил после огромного перерыва. Т.е. пришлось восстанавливать в памяти много информации.

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

А далее расскажу о том, что происходило во время перерыва занятий.

3. Перерыв в обучении IT

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

Интернет-мем
Интернет-мем

Перерыв был вызван огромным объёмом работы на текущей работе. Из интересного - побывал на чемпионате профессионального мастерства в Сколково по компетенции "Аддитивное производство" Госкорпорации Ростех, см. несколько фото в ленте.

По итогам чемпионата мы с экспертным сообществом задумались об импортонезависимом ПО для чемпионата. Я предложил начать с операционной системы: перейти на Linux. А ещё нужны CAD-программы, слайсеры, ПО для реинжиниринга.

Также, хотя на море толком не удалось побывать этим летом - но в одном из предыдущих постов рассказывал о сотрудничестве с университетом по части НИОКТР. Там ребята помимо работы с "железом" активно пишут ПО на различных ЯП, и один из полезнейших инструментов - нейросетки.

С этим проектом мы должны участвовать на Восточном экономическом форуме ВЭФ-2023 в г.Владивосток, на о.Русский. На этой неделе ездил туда чтобы привезти и собрать макет оборудования, которое разрабатываем и изготавливаем по НИОКТР. А поскольку выставка пройдёт на набережной Японского моря, я немного разрушил мем выше, см. ленту из фото ниже.

На выставке только в павильоне Приморского края будет 85(!) научно-технических проекта, в т.ч. по IT-сфере. Будет интересно разузнать всё как есть, что интересного в IT происходит у нас в регионе. А ведь там будет множество павильонов из других краёв, а может и стран. Хз, впервые буду на ВЭФе.

Вот такие дела. Ещё этим летом познакомился с классной девушкой и успел в неё влюбиться - правда, она сказала, что я не айтишник. Все айтишники, говорит, замкнутые. Ну хз. Успел с ней расстаться уже. По другой причине. Как говориться, спасибо за всё хорошее.

Встретил одноклассника - он работает на машине литья под низким давлением в литейном цеху. Узнал, что он увлёкся IT - учился на тестера. Рассказал ему о Go, он загорелся и со следующей неделе начнёт изучать. Поглядим, к чему это приведёт.

А сейчас я тебе говорю "Успехов, бро!". Спасибо, что дочитал публикацию до конца. Будем на связи.

Jeremy Bishop - https://unsplash.com/photos/pikyGuAmwpM
Jeremy Bishop - https://unsplash.com/photos/pikyGuAmwpM

Бро, ты уже здесь? 👉 Подпишись на канал для новичков «Войти в IT» в Telegram, будем изучать IT вместе 👨‍💻👩‍💻👨‍💻