Отслеживание конкретного файла

С помощью inotify можно мониторить не только папки, но и просто файлы. Для этого создавая watch_fd, просто укажите полный путь к файлу

int watch_fd = inotify_add_watch(inotify_fd, "/home/m/file.txt", IN_MODIFY);

в этом случае, при событии, у вас уже не будет имени файла event->name, но вы можете проверить, о каком файле пришло событие изменения сравнив event->wd с watch_fd

Если они совпали значит событие пришло о файле который мониторится с помощью watch_fd

int length = read(inotify_fd, buffer, EVENT_BUF_LEN);
int i = 0;
while (i < length)
{
    struct inotify_event *event = (struct inotify_event *)&buffer[i];
    if (event->mask & IN_MODIFY && event->wd == watch_fd) {
        cout << "файл изменился" << endl;
    }
}

Отключение события отслеживания

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

inotify_rm_watch(inotify_fd, watch_fd);

если же захотите включать отслеживание обратно, то просто еще раз вызовите

watch_fd = inotify_add_watch(inotify_fd, "/home/m/file.txt", IN_MODIFY);

Вызов bash команды из C++ и перехват вывода

Часто есть необходимость выполнить bash команду и вывод этой команды использовать в своей программе.

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

std::string exec(string cmd) {
    std::array<char, 128> buffer; // буфер для перехвата вывода команды
    std::string result; // переменная в которой будет хранится итоговый полный вывод команды
    std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose); // создаем процесс
    if (!pipe) {
        throw std::runtime_error("popen() failed!");
    }
    while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { // и пока команда генерит текст
        result += buffer.data(); // подклеиваем его к нашей переменной result
    }
    return result;
}

Как ее использовать?

Например, хочу я запустить ls, тогда мне надо будет написать так

#include <iostream>
#include <sys/inotify.h>
#include <unistd.h>
#include <array> // добавил для работы с буффером
#include <memory> // добавил для работы с процессами

using namespace std;

// это скопипастил
std::string exec(string cmd) {
    std::array<char, 128> buffer; // буфер для перехвата вывода команды
    std::string result; // переменная в которой будет хранится итоговый полный вывод команды
    std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose); // создаем процесс
    if (!pipe) {
        throw std::runtime_error("popen() failed!");
    }
    while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { // и пока команда генерит текст
        result += buffer.data(); // подклеиваем его к нашей переменной result
    }
    return result;
}

int main(int argc, char* argv[]) {
	string result = exec("ls -la ."); // вызываем нашу функцию с командой которую хотим запустить
	cout << "Вы запустили команду и она выдала:" << endl;
	cout << result << endl;
	return 0;
}

теперь если запустить эту программу увидим

то есть казалось бы, ничего такого. Но хитрость в том, что список файлов, которые мы видим это прост текстовое содержимое переменной result.

А переменную заполнила функцию exec. Вот такие вот дела.

Теперь попробуйте собрать из всей этой кучи кода задание

Задание

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

  • cowsay
  • figlet

то есть вы например пишите в файл Привет а программа преобразует содержимое файла в

 ________
< Привет >
 --------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||