Как стать автором
Обновить

Программирование на C в Linux на примере создания своей командной оболочки

Уровень сложностиСредний
Время на прочтение27 мин
Количество просмотров16K
Всего голосов 28: ↑25 и ↓3+36
Комментарии42

Комментарии 42

По моему самое главное в терминале - это создание пары pty master и pty slave и ее соответствующая настройка. Вы не стали ее использовать?

Я не стал. Даже если честно не знал о них, я порылся в некоторых других репозиториях даже, нету такого(

Так он же пишет не эмулятор терминала (xterm, Konsole, xfce-terminal, Gnome Terminal) и другие инструменты (tmux, screen), которые сопоставляют псевдотерминальные дескрипторы с выводом конкретного приложения, а командный интерпретатор для которого уже это это сделано эмуоятром терминала.

Свой minishell пишут на 5 уровне ( из 21 ) в школе21

И на Гите есть куча тестов. ( minishell ecole42 test )

Прогоните хоть какой

У меня как раз идет разработка обновления, планирую добавить пайплайны, редиректы

инициализирует его до нуля

что простите? до какого нуля? кроме того в описаниях появляются разные еклмнэейки при том что показанные вами сигнатуры не принимают аргументов.

И именно благодаря более свободной лицензии, чем GNU GPL (открытость не значит свобода).

более свободный это уже public domain, что явно не относится к большинству подобного софта.

(kolibri os, os/2) используется именно gcc.

kolibri вообще на ассемблере пишется и компилятор их ассемблера написан на нём же и к gcc отношения как такового не имеет.

if (strcmp(color_name, "RED") == 0) { color_value = RED; } else if (strcmp(color_name, "GREEN") == 0) { color_value = GREEN; } else

а чего их вам в статичный массив не поскладировать и циклом проверять? два десятка стрёмных строчек превращаются в красивый список, цикл и одну стрёмную строчку.

fprintf(stderr, "%s%s%s%s%s %s\n", RESET,

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

fprintf(stderr, RESET "%s%s%s" RESET " %s\n"
        , color, format, msgtype_string, message);

Т.к. макрос также развернётся в строковый литерал.

Спасибо, учту, в следующей части изменю

Не слушай его, статический массив с строками и цикл по ним с strcmp - ничем не лучше.
Сравнить int гораздо быстрее, чем сравнить строку, поэтому в идеале - enum с значением-индексом к статичному массиву с строками-цветами.

т.е.

enum { COLOR_NONE, ... тыры пыры

COLOR_END
Затем

const char *colors[] = {
"\e[0m",
...

...
NULL
}

Примерно так. Главное чекнуть, что пришедший индекс В диапазоне
COLOR_END <= ind < COLOR_END
Если да - colors[ind].

Спасибо, а то я думал как можно получше сделать)

Строки он в любом случае станет сравнивать т.к. насколько я понимаю это часть парсинга чего-то и просто проиндексировать их enum не выйдет ибо нужно ещё придумать как 0..n замаппить на некоторый хэш от строки. Ну и всякие границы проверять опять же - больше ненужного кода. А так

char* get_color_by_name(const char* color_name) {
  struct { char *text, *code; } colors[] = {
    {.text="RESET"  , .code = RESET  },
    {.text="BLACK"  , .code = BLACK  },
    {.text="RED"    , .code = RED    },
    {.text="GREEN"  , .code = GREEN  },
    {.text="YELLOW" , .code = YELLOW },
    {.text="BLUE"   , .code = BLUE   },
    {.text="MAGENTA", .code = MAGENTA},
    {.text="CYAN"   , .code = CYAN   },
    {.text="WHITE"  , .code = WHITE  },
    {.text="GRAY"   , .code = GRAY   },
  };
  const int len = sizeof(colors)/sizeof(colors[0]);
  for (int i =0; i < len; ++i) {
    if (strcmp(color_name, colors[i].text) == 0) {
      return colors[i].code;
    }
  }
  return NULL;
}

Маппинги/хардкод отдельно, поиск отдельно ещё и код на четверть короче при ровно той же производительности. Расширять тоже проще - просто добавил строчку в таблицу и готово.

Спасибо, ваш вариант мне понравился. Даже не поленились написать код!

Аналогично следует поступить и с интерпретатором команд - вместо длинной цепочки if/else вставить проверку по массиву и вызов реализующей функции по указателю. Код существенно согратиться, будет более понятен и легко расширяем.

Можно пойти еще чуть дальше - в массив с командами добавить строки с описанием команды (подсказка) и отображать подсказку если команда пришла без требуемых параметров.

Цветовую раскраску следует отключать если работа идет не с интерактивным терминалом.

Статья хороша. спасибо!

обла1дает обширной

А ещё у вас опечатка)

Thanks very much

Это статья а не книга.
Зачем здесь "Краткая история С", "Краткие основы C", "Компиляторы: gcc или clang"?
В данном контексте мало того что бесполезно, так еще и вредно:
- размерность базовых типов в стандарте плавающая и указано лишь отношение размерностей. (int >= short, short >= char). Внезапно на некоторых платформах char может оказаться размером 32бита.
- про char лучше думать как о третьем типе на равне с unsigned char, signed char. к какому типу char будет приводится зависит от конкретной реализации компилятора под конкретную платформу. (смотрим описание аргументов к gcc: -funsigned-char, -fsigned-char)
- выбор компилятора зависит от тех условий и других ограничений, а не от "свободная свобода"
- "Для адресов в памяти применяется шестнадцатеричная система." - адрес записанный в память хранится в бинарном виде. 0/1, есть заряд/нет заряда, ... (исключением наверное является компьютер "сетунь", ну и сложные способы хранения информации в современных флеш)

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

Для всего остального: что бы вникнуть в основы написания оболочек под linux есть замечательная книга "Linux Application Development, 2ed, Michael K. Johnson, Erik W. Troan", ну или в переводе "Разработка приложений в среде Linux. Программирование для Linux, 2-е издание, Майкл К. Джонсон, Эрик В. Троан"

Насчет методички вы не правы, кратко нашел информацию. А за книги спасибо, почитаю.

А разделы я вставил для того чтобы внести ясность, ну и чтобы заголовок не был кликбейтом.

Благодарю.

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

КМК автор переборщил с использованием нейросети и ему стало жалко вырезать эту воду из статьи. Взгляните на код:

char* read_user_input(void) {
	rl_getc_function = getc;
	fflush(stdout);

	// Буфер ввода (то есть получаем вывод через readline с новой строки с окрашиванием в цвета для красоты)
	char* input_buffer = readline("\n\033[2m╰─>\033[0m\033[0;36m $ \033[0m");

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

Кстати, этот код только приведен только в статье, в репе реализация уже другая.

Про кучу опечаток и странных речевых оборотов я вообще молчу. С самого начала:

И его знать, нет, не обходимо, но довольно желательно.

Я запутался от такого отрицания отрицания.

BINARY_NAME = shegang

А это у китайцев взято, или у чатгпт, который сходил к китайцам?

В репе код другой, ибо я уже успел запилить обновление, вырезать многое, поменять либу с readline на isocline.

Насчет мейкфайла - у меня всегда есть BINARY_NAME или похожее название.

Для текста я никогда не использую чатгпт, иначе заминисуют

Внезапно на некоторых платформах char может оказаться размером 32бита.

Не может, стандарт гарантирует, что sizeof(char) == 1. Другое дело, что char может оказаться, как знаковым, так и беззнаковым (зависит от архитектуры процессора, ОС и даже версии компилятора). Так что если нужен байт, то лучше взять типы uint8_t или int8_t.

Я понимаю, стандарты читать сложно. Возмем к примеру С11 (ISO/IEC 9899:2011)
6.2.5
An object declared as type char is large enough to store any member of the basic execution character set. If a member of the basic execution character set is stored in a char object, its value is guaranteed to be nonnegative. If any other character is stored in a char object, the resulting value is implementation-defined but shall be within the range of values that can be represented in that type.

Тип char должен быть для хранения базового набора символов. Базовый нобор символов описан в секции 5.2.1

3.7.1
character
single-byte character
〈C〉 bit representation that fits in a byte


тоесть char это единичный байт

3.6
byte
addressable unit of data storage large enough to hold any member of the basic character
set of the execution environment
NOTE 1 It is possible to express the address of each individual byte of an object uniquely.
NOTE 2 A byte is composed of a contiguous sequence of bits, the number of which is implementation-defined. The least significant bit is called the low-order bit; the most significant bit is called the high-order bit.


В понимании стандарта byte это последовательность бит количество которых зависит от реализации. Тоесть не обязательно 8бит.

5.2.4.2.1 Sizes of integer types <limits.h>
...
Their implementation-defined values shall be equal or greater in magnitude (absolute value) to those shown, with the same sign.
— number of bits for smallest object that is not a bit-field (byte)
CHAR_BIT 8

Есть файл limits.h в котором будут описаны размеры целочисленных типов в том числе и char. И что эти значения могут быть равными или больше по абсолютному значению представленному в стандарте.
Тоесть char моежет быть 8бит а может и больше. Зависит о конкретной реализации.


Теперь перейдем в пример к конкретной реализации:
Texas Instruments C54x DSPs. Есть gcc и binutils. Процессор специального назначения, оперирует с данными минимальным размеров 16бит в том числе и адресация. здесь char == 16бит.

Во времена создания языка С, байт размерностью в 8 бит не был широко распространет. Существовал целый зоопарк желеха с разной размерностью байта. Я язык перетендовал на широкую переносимость програм. Сейчас в основном попадаются специализированные решения с байтом отличным от 8 бит.

Наверное понимание одного байта.

sizeof(T) равен некоему размеру в sizeof(char), который принят за базу отчёта (единицу) и равен одному байту, размер в битах этой единицы - платформозависимый.

Понравилось про clang лучше gcc) Особенно когда автор слабо понимает различия между двумя этими монстрами и вставил свои пять копеек, потому что шланг "модный", а гцц - легаси, нарушающий стандарты. Так вот вьюноша, сам по себе gcc(как си компайлер) является основой, и стандартом де-факто, сам по себе. Все фишки обкатываются в ядре Линукс и в libc, а потом уже закладываются в стандарт. И гцц тоже кстати, имеет модульную структуру, и ничем особо в этом не отличается от шланга.

Спасибо, учел. Соглашусь с вами, шланг модный, и я не раз слышал, что пора отказываться от GCC в пользу clang.

		// переходим на следующую итерацию если возвращено NULL
		if (line == NULL) {
			free(line);      /* <---------------- !!! */
			continue;
		}

Надо поправить)) Не ошибка, free прощает NULL, но глаз дернулся))

НЛО прилетело и опубликовало эту надпись здесь

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

на начало которого указывает указатель bl

– А почему "bl"?

– Чтобы никто не догадался!

На нейросеть не похоже. Слишком безграмотный русский язык. Тяжело читать.

я наблюдаю за этим автором уже наверно год. Он умудряется иногда генерировать по две получасовые статьи в день! При этом успевает отвечать в коментариях в интонациях школьника.

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

Ну хз. Такое чудовищное косноязычие и безграмотность - странный проект получается.

Ну что-ж, господа судебные заседатели, буду развиваться

куда же вам еще развиваться то, если вы уже и так в состоянии писать по две статьи в день, или просто очень часто, по десяткам не связанных тем!

Вы меня пугаете :) !

Да, вам желательно какое-то время серьезно поработать над собой. Непублично. Потом возвращайтесь, пишите.

Была одна статья в которой был сплошной бред про многопоточность, они ее убрали после критики.

я совершенно согласен с вашей оценкой, но в этой конкретной статье хотя бы есть что-то полезное в агрегированной таким образом информации, неужели только за это что-то полезное ее заплюсовали?

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

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

Генерировать по 2 статьи большие в день у меня никак не получалось, да и не вышло бы.

ну вот же:

6 дек 2023 в 18:59

6 дек 2023 в 16:02

5 дек 2023 в 17:25

Но да не по полчаса 7мин и 11 мин, но это тоже достаточно много, если учесть еще что это не связанные темы. Хотя вы конечно могли их подготовить заранее...

Clang поддерживает все стандарты во всех деталях? Но ведь даже на оф.сайте сказано, что последние стандарты пока только частично, и ещё ладно с C++17, так с C обстоит ещё печальнее.

Спасибо, учту. Я почему то думал что clang поддерживает все стандарты...

Зарегистрируйтесь на Хабре, чтобы оставить комментарий