The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]



"Селектор и повторитель-запускатель команд из .bash_history"
Вариант для распечатки  
Пред. тема | След. тема 
Форум Программирование под UNIX (C/C++)
Изначальное сообщение [ Отслеживать ]

"Селектор и повторитель-запускатель команд из .bash_history"  +/
Сообщение от dcc0 (ok), 24-Янв-25, 01:25 
Если время есть - минут 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_history

  file = 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;
}


  

Ответить | Правка | Cообщить модератору

Оглавление

Сообщения [Сортировка по времени | RSS]


1. "Селектор и повторитель-запускатель команд из .bash_history"  +/
Сообщение от shadow_alone (ok), 24-Янв-25, 08:49 
А зачем собственно кривой велосипед, если есть Ctrl-r и fc?
Ответить | Правка | Наверх | Cообщить модератору

2. "Селектор и повторитель-запускатель команд из .bash_history"  +/
Сообщение от dcc0 (ok), 24-Янв-25, 12:00 
> А зачем собственно кривой велосипед, если есть Ctrl-r и fc?

Ctrl-r и fc по-другому работают.

Именно поэтому попросил протестировать.
Компиляция простая, к примеру так:
gcc select_history.c -o select_history.o
Запуск из директории пользователя.
./select_history.o

Ответить | Правка | Наверх | Cообщить модератору

3. "Селектор и повторитель-запускатель команд из .bash_history"  +/
Сообщение от Аноним (3), 24-Янв-25, 19:30 
А history и !номер   ?
Ответить | Правка | Наверх | Cообщить модератору

4. "Селектор и повторитель-запускатель команд из .bash_history"  +/
Сообщение от dcc0 (ok), 24-Янв-25, 20:32 
> А history и !номер   ?

Почти. Но смысл чуть-чуть другой. Так выполнил и завершил, а так остался в программе.
Т.е. выполнил, одно, затем другое, допустим, так.
И переход по разрядам. Т.е. допустим, выполнил 10 команду, затем добавил 0 и оказался сразу на 100 позиции, выполнил тут что-то.
Т.е. эта штука может висеть фоном на терминале.

Добавил перелистывание на 30 позиций вперед/назад на боковые стрелки:
https://gitflic.ru/project/dcc0/select-and-run/blob/?file=se...

Ответить | Правка | Наверх | Cообщить модератору

5. "Селектор и повторитель-запускатель команд из .bash_history"  +/
Сообщение от shadow_alone (ok), 25-Янв-25, 01:12 
Вы действительно считаете что кто-то выполняет N-ное количество раз одни и те же комманды, бродит по истории, выбирает и выполняет?
Бред какой-то.
Поиск реализован давно уже, замена так же реализована, исполнение по номеру тоже.

Найдите себе другую идею, эту уже так обсосали, что нет шансов.

Ответить | Правка | Наверх | Cообщить модератору

Архив | Удалить

Рекомендовать для помещения в FAQ | Индекс форумов | Темы | Пред. тема | След. тема




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2025 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру