Если время есть - минут 5, хочу попросить кого-нибудь протестировать программу и сказать своё мнение. Но не по коду, а больше по самому функционалу.
Программа для Linux. Написана на C. Реализует возможность просмотра и выполнения команд из файла .bash_history по номеру.Управление: s - сброс, клавиши 0-9 (можно переходить по разрядам) - переход к номеру команды. Стрелки вверх и вниз - переход к ближайшим командам. Выход 501 или "`".
Работает из директории пользователя. Прокрутки нет (только стрелки), но если нужна, то можно использовать в сочетании с tmux:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////ПОИСК И ЗАПУСК КОМАНД ИЗ .BASH_HISTORY/////
//////////MSK. 2025///////
//////////Сrafted by: dcc0@yandex.ru///////////
/////////MoLoT////////
//////////Принцип: селектор, выбор через цифры. Enter: подтверждение//////////
////////////////////////////////////////////////////Рассчитан на 500 строк .bash_history/////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>#include <stdlib.h>
#include <termios.h>
#include <string.h>
#include <unistd.h>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*Перевод в режим non-canonical, getch работает без Enter. Этот фрагмент кода взят в Интернете*/
//This function found on stackoverflow
//////////////////////////////////////////////SWITCH TO NON-CANONICAL///////////////////////
/////////////////////////////////////////////////////////ФУНКЦИЯ////////////////////////////////////////////
/////////SOURCE: stackoverflow.com SLASH questions/63751531/non-canonical-terminal-mode-buffer-stdout-in-c-program//////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static struct termios stored_settings;void set_keypress(void) {
struct termios new_settings;tcgetattr(0, & stored_settings);
new_settings = stored_settings;
/* Disable canonical mode, and set buffer size to 1 byte */
new_settings.c_lflag &= (~ICANON);
new_settings.c_cc[VTIME] = 0;
new_settings.c_cc[VMIN] = 1;tcsetattr(0, TCSANOW, & new_settings);
return;
}void reset_keypress(void) {
tcsetattr(0, TCSANOW, & stored_settings);
return;
}///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////Вызов Селектора/////////////////
///////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////ФУНКЦИЯ////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Функция вывода селектора. Возвращает название программы
char * print_select(int select, char * p, char arr1[500][200], int z) {
int j = 0;
/*Выделение цветом*/
char colored[14] = "\033[43m";
/*Сброс цвета*/
char uncolored[14] = "\033[0m";//====ВЫВОДИМ СЕЛЕКТОР===
/*Очистим экран. Обновим. Первый раз выводим*/
system("clear");
if (select == 0) {
/*Количество вариантов выбора в переменной z*/
for (j = 0; j != z; j++) {
printf("%d.[%s]\n", j + 1, arr1[j]);
}
}//====ЕСЛИ СДЕЛАН ВЫБОР===
int choice = select - 1;
// Выводим результат выбора
if (select > 0) {
for (j = 0; j < z; j++) {
// Выделяем цветом выбор
if (select == j && select != 501) {
// Запомним выбор. Нужно, чтобы напечатать в правильно
// последовательности так как селектор с 1 по 6, массив с 0 по 5
choice = select - 1;
printf("->[%s%s%s]\n", colored, arr1[select - 1], uncolored);
/* Возвращаем указатель на область памяти, где эта строка. Заодно
* выделили память под нее (strlen - если не известен размер)*/
//p = (char * ) malloc(strlen(arr1[select - 1]) + 1);
//Но мы знаем размер 20. char * - приведение к типу "указатель на строку"
p = (char * ) malloc(400);
strcpy(p, arr1[select - 1]);
break;
}
if (j != choice) printf("%d.[%s]\n", j + 1, arr1[j]);
}//Последнюю опцию добавим вне цикла
if (select ==500) {
printf("->[%s%s%s]\n", colored, arr1[select - 1], uncolored);
p = (char * ) malloc(400);
strcpy(p, arr1[select -1]);
}}
printf("Для выхода: ` или 501 \n");
printf("Для сброса нажмите букву: s \n");
printf("Если трехзначное число, то нажатие s обнулит буфер!\n");/*Вернем название программы, которую надо выполнить*/
if (p != "")
return p;
return "1";
}//////////////////////////////BUFFERING ////////////////////////////////
////////////////////////////БУФЕРИЗАЦИЯ ФАЙЛА//////////////////////////
/////////////////////////////////////////////ФУНКЦИЯ/////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
char * buffering (char arr1[500][200], int z_size ) {
///////////////////////////////////////////////////////////////////////////////////////////
//==================READING FILE============//
/////////////////////////////////////////////////////////////////////////////////////////
// Читаем файл с программами 1 раз. Потом будем хранить в буфере arr1
FILE * file;
char buffer1;
char str[200];
int i = 0;
/*Количество вариантов*/
int z = 0;
int j = 0;
// Количество показываемых файлов. Массив. Буфер для .bash_historyfile = fopen(".bash_history", "r");
while ((buffer1 = getc(file)) != EOF) {
if(z==500)
break;
str[i] = buffer1;if (str[i] == '\n') {
// Пишем строку посимвольно в отдельный массив
for (j = 0; str[j] != '\n'; j++) {
arr1[z][j] = str[j];
}
/*Запишем 0 в конец строки*/
arr1[z][j] = '\0';
z++;
//Сбросим i , чтобы очистить str[0]
//Так как ниже инкремент, то сбросим в -1, т.е. ниже i уже = 0
//Иначе в str[0] всегда будет в начале первый символ
i = -1;
}
i++;
}fclose(file);
//Вернем указатель на массив
return * arr1;}
////////////////////////////////MAIN///////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
////////////////////////////////////ФУНКЦИЯ//////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int main(void) {////////////////////////////////KEYS//////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////УПРАВЛЕНИЕ/////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
char const KEY_A='A'; //Стрелка вверх
char const KEY_B='B'; //Стрелка вниз
char const KEY_s='s'; //Сброс
char const KEY_EXIT='`'; //Выход (`)
char const KEY_SPACE=' '; //Пробел
char const KEY_ENTER='\n'; //Enter
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////Массив хранит .bash_history
char arr1[500][200];
//Функция буферизации
buffering(arr1, 500);
//Размер массива - буфера
int z = 500;
///////////////////////////////////////////////////////////////////////////////
char * run_program;
//для названия команды
char * p;
//Цвет
char colored[14] = "\033[43m";
/*Сброс цвета*/
char uncolored[14] = "\033[0m";
int select = 0;
//Вызываем селектор 1 раз, пустой
print_select(select, p, arr1, z);
//С помощью terminos переключим вывод терминала в non-canonical mode.
//Это позволит не нажимать Enter при переходе от опции к опции, но для выполнения нажать надо
set_keypress();
//Для чтения с терминала
char value = getchar();
//Для перемещения по разрядам
char buffer[3] = {0};
//Счётчик буфера
int i = 0;
int y = 0;
//////////////////////////////////////////////////////////////////////////////////
////////////////////////СЕЛЕКТОР В ЦИКЛЕ////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////while (1) {
//////////////////////////////////////////////////////////////////////////////////
///////////////////УПРАВЛЕНИЕ СТРЕЛКАМИ///////////////////
//////////////////////////////////////////////////////////////////////////////////
//Листаем вниз
if (value == KEY_B) {
y++;
value = KEY_SPACE;
select=select+y;
run_program = print_select(select, p, arr1, 500);
select=0;
}//Листаем вверх
if (value == KEY_A) {
y--;
value = KEY_SPACE;
select=select+y;
run_program = print_select(select, p, arr1, 500);
select=0;
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////if (value != KEY_SPACE && value != KEY_s) {
buffer[i] = value;
value = KEY_SPACE;
//Приведем к int
select = strtol(buffer, NULL, 10);
//Вызываем селектор с выбором
run_program = print_select(select, p, arr1, 500);
i++;
//Освободим память
//free(run_program);
}
///////////////////////////////////////////////////////////////////////////////
//Проверим буфер. Если буфер заполнен, то обнулим его. Напечатаем то что в нем было в начале
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//Проверим буфер. Если буфер заполнен, то обнулим его. Напечатаем то что в нем было в начале
//Можно описать циклом, но оставим всё явно для наглядности
//Тут конъюнкция (логическое "и", логическое сложение, в курсе булевой алгебры или логики:))
if (value != KEY_A && value != KEY_B && y == 0) {
if (buffer[0] > 0 && buffer[1] == 0) {
printf("%c", buffer[0]);}
if (buffer[0] > 0 && buffer[1] > 0 && buffer[2] == 0) {
printf("%c %c", buffer[0], buffer[1]);}
if (buffer[0] > 0 && buffer[1] > 0 && buffer[2] > 0) {
printf("%c %c %c", buffer[0], buffer[1], buffer[2]);}
value = KEY_SPACE;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//Добавляем новое число в буфер
if (buffer[i] > 0) {
//Чтобы не получить stack smashing
if (i >= 3) {
i = 3;
}
buffer[i] = value;
}//Ожидаем ввод
value = getchar();
//Выполним программу
//Проверим, что нажат Enter (\n) и то, что не выходим
if (value == KEY_ENTER && select !=501) {
system(run_program);
//Чтобы остановить обновление
//и показать результат программы
value = KEY_SPACE;
}
//Обнулим проход (для наглядности все опишем явно)
if (value == KEY_s && select!=501) {
//Обнулим буфер
buffer[0] = 0;
buffer[1] = 0;
buffer[2] = 0;
//Обнулим счётчик буфера
i = 0;
select = 0;
y = 0;
print_select(select, p, arr1, z);
}
//Выход (дизъюнкция - нестрогое "или". Или то, или то. Если первое условие верно, то второе не проверяется)
if (value == KEY_EXIT || select==501) {
break;
}}
printf("\033[43m Выход \033[0m \n");
return 0;
}
А зачем собственно кривой велосипед, если есть Ctrl-r и fc?
> А зачем собственно кривой велосипед, если есть Ctrl-r и fc?Ctrl-r и fc по-другому работают.
Именно поэтому попросил протестировать.
Компиляция простая, к примеру так:
gcc select_history.c -o select_history.o
Запуск из директории пользователя.
./select_history.o
А history и !номер ?
> А history и !номер ?Почти. Но смысл чуть-чуть другой. Так выполнил и завершил, а так остался в программе.
Т.е. выполнил, одно, затем другое, допустим, так.
И переход по разрядам. Т.е. допустим, выполнил 10 команду, затем добавил 0 и оказался сразу на 100 позиции, выполнил тут что-то.
Т.е. эта штука может висеть фоном на терминале.Добавил перелистывание на 30 позиций вперед/назад на боковые стрелки:
https://gitflic.ru/project/dcc0/select-and-run/blob/?file=se...
Вы действительно считаете что кто-то выполняет N-ное количество раз одни и те же комманды, бродит по истории, выбирает и выполняет?
Бред какой-то.
Поиск реализован давно уже, замена так же реализована, исполнение по номеру тоже.Найдите себе другую идею, эту уже так обсосали, что нет шансов.
> Вы действительно считаете что кто-то выполняет N-ное количество раз одни и те же коммандыПффф. Это называется скрипты. А у автора хз ваще что и зачем ))
Чтобы не растекаться мыслию по древу, - видео, как это работает:
https://www.youtube.com/watch?v=8-6RoZXjkqE