LINUX.ORG.RU

Отслеживание изменения прав доступа на несколько файлов, проблема с индексами

 , , ,


0

1

Всем добрый день. Нужна ваша помощь. Дали задание создать скрипт на языке Bash, который в режиме реального времени отслеживает изменение прав доступа на несколько конечных файлов в поддереве указанного каталога и выводит информацию про изменение в файл и терминал. В качестве аргументов скрипту я передаю адрес каталога и имена файлов (пример аргументов: /home/computer/myfolder file2.txt file1.txt some.txt).

Код рабочий, но есть проблема. В некоторых случаях при выполнении скрипт моментально выдает, что права доступа изменились. При этом я права доступа не менял. Не знаю с чем это связано. Вроде бы когда файл только создан с правами доступа по умолчанию, то работает нормально. Как только изменяю на другие и заново запускаю скрипт, то выдает, что права доступа изменились. А также например, если я передаю файлы в порядке «file2.txt file1.txt some.txt», то проблема сохраняется. Если я передаю файлы в порядке «file1.txt file2.txt some.txt», то такой проблемы не возникает (some.txt находится в подкаталоге указаного каталога).

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

Код скрипта:

#!/bin/bash

# Первый аргумент – путь к каталогу, который будет проверяться
dir_path="$1"
shift

# Проверка, существует ли заданный каталог и не пустует ли
if [ ! -d "$dir_path" ] || [ -z "$dir_path" ]; then
    echo "Неправильно заданный каталог!"
    exit 1
fi

# Список файлов для проверки
file_list=("$@")

# Проверка, пустой ли список файлов
if [ ${#file_list[@]} -eq 0 ]; then
    echo "Отсутствует список файлов для проверки!"
    exit 1
fi

# Ассоциативный массив для сохранения путей к файлам
declare -A file_paths

# Поиск путей к файлам в каталоге и его подкаталогах
for file in "${file_list[@]}"; do
    file_paths["$file"]=$(find "$dir_path" -path "*/$file" -print -quit)

    # Проверка, был ли найден файл
    if [ -z "${file_paths["$file"]}" ]; then
        echo "Файл $file не найден в $dir_path и подкаталогах"
        exit 1
    fi
done

# Имя файла журнала изменений прав доступа
log_file="permissions_log_$(date +%Y%m%d_%H%M%S).txt"
touch "$log_file"

# Массив для сохранения старых прав доступа к файлам
old_perm=()

# Запись старых прав доступа к файлам
for file in "${!file_paths[@]}"; do
    old_perm+=("$(stat -c '%a' "${file_paths[$file]}")")
done

# Бесконечный цикл для проверки прав доступа с определенной задержкой
while true; do
    new_perm=()
    for i in "${!file_list[@]}"; do
        file="${file_list[$i]}"
        new_perm+=("$(stat -c '%a' "${file_paths[$file]}")")
        # Сравнение новых и старых прав доступа
        if [ "${new_perm[$i]}" != "${old_perm[$i]}" ]; then
            timestamp=$(date +"%Y-%m-%d %H:%M:%S")
            # Вывод сообщения об изменении прав доступа и запись в журнал
            echo "$timestamp | Права доступа для файла $file из каталога ${file_paths[$file]} изменились с ${old_perm[$i]} на ${new_perm[$i]}"
            echo "$timestamp | Права доступа для файла $file из каталога ${file_paths[$file]} изменились с ${old_perm[$i]} на ${new_perm[$i]}" >> "$log_file"
            old_perm[$i]="${new_perm[$i]}"
        fi
    done
    sleep 1
done

Конечно, давайте исправим ошибку в вашем скрипте. Проблема заключается в том, что вы используете индексы массива new_perm, которые не соответствуют индексам массива old_perm, когда сравниваете права доступа.

Вот исправленный скрипт:

#!/bin/bash

dir_path="$1"
shift

# Проверка, существует ли заданный каталог и не пустует ли
if [ ! -d "$dir_path" ] || [ -z "$dir_path" ]; then
    echo "Неправильно заданный каталог!"
    exit 1
fi

# Список файлов для проверки
file_list=("$@")

# Проверка, пустой ли список файлов
if [ ${#file_list[@]} -eq 0 ]; then
    echo "Отсутствует список файлов для проверки!"
    exit 1
fi

# Ассоциативный массив для сохранения путей к файлам
declare -A file_paths

# Поиск путей к файлам в каталоге и его подкаталогах
for file in "${file_list[@]}"; do
    file_paths["$file"]=$(find "$dir_path" -path "*/$file" -print -quit)

    # Проверка, был ли найден файл
    if [ -z "${file_paths["$file"]}" ]; then
        echo "Файл $file не найден в $dir_path и подкаталогах"
        exit 1
    fi
done

# Имя файла журнала изменений прав доступа
log_file="permissions_log_$(date +%Y%m%d_%H%M%S).txt"
touch "$log_file"

# Ассоциативный массив для сохранения старых прав доступа к файлам
declare -A old_perm

# Запись старых прав доступа к файлам
for file in "${!file_paths[@]}"; do
    old_perm["$file"]=$(stat -c '%a' "${file_paths[$file]}")
done

# Бесконечный цикл для проверки прав доступа с определенной задержкой
while true; do
    for file in "${!file_paths[@]}"; do
        new_perm=$(stat -c '%a' "${file_paths[$file]}")

        # Сравнение новых и старых прав доступа
        if [ "$new_perm" != "${old_perm[$file]}" ]; then
            timestamp=$(date +"%Y-%m-%d %H:%M:%S")
            # Вывод сообщения об изменении прав доступа и запись в журнал
            echo "$timestamp | Права доступа для файла $file из каталога ${file_paths[$file]} изменились с ${old_perm[$file]} на $new_perm"
            echo "$timestamp | Права доступа для файла $file из каталога ${file_paths[$file]} изменились с ${old_perm[$file]} на $new_perm" >> "$log_file"
            old_perm["$file"]="$new_perm"  # Обновление значения в массиве
        fi
    done
    sleep 1
done

Основные изменения:

Ассоциативный массив old_perm: Теперь это ассоциативный массив, где ключами являются имена файлов, а значениями – старые права доступа. Это позволяет избежать путаницы с индексами.

Сравнение прав доступа: В цикле for мы напрямую сравниваем new_perm с old_perm[$file], используя имя файла в качестве ключа.

Обновление old_perm: После обнаружения изменения прав доступа значение в массиве old_perm обновляется, чтобы в следующий раз сравнение было корректным.

Теперь скрипт должен работать корректно, независимо от порядка файлов в аргументах.

anonymous
()

Чот ты дичь накрутил. Бери

ls -1l

сохраняй в переменную, потом старое и новое значение прогоняй через diff

cobold ★★★★★
()

У тебя все неправильно. Перепиши на питоне. Примерно такой алгоритм:

_listeners: set[Callable] = set()
# ключ полный путь, значение - хеш от содержимого
previous_files = find_files(watch_directory)
while True:
  try:
    current_files = find_files(watch_directory)
    # вычисляешь разницу между previous и current_files
    created = ...
    updated = ...
    deleted = ...
    # for listener in _listeners: listener(args)
    notify(created, updated, deleted)
    previous_files = current_files
  finally:
    time.sleep(0.2)
anonymous
()
Ответ на: комментарий от anonymous

В итоге должно получиться такое:

def guard(created, updated, deleted):
  ...

watcher = FileWatcher()
watcher.add_listener(guard)
watcher.watch(path) # runs forever loop
anonymous
()
Ответ на: комментарий от anonymous

Зачем тебе все события если inotify умеет конкретно IN_ATTRIB?

anonymous
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.