Получить последнюю запись на основе даты в файле

Ранее я написал комментарий о следующем подходе:

sudo mount -t tmpfs -o size=1g tmpfs /mnt/tmpfs
sudo mkdir /mnt/tmpfs/sshfs
sudo sshfs rowan@10.0.5.5:/home/rowan/sshfs /mnt/tmpfs/sshfs/.

Здесь мои результаты:

tmpfs                             1.0G     0  1.0G   0% /mnt/tmpfs
rowan@10.0.5.5:/home/rowan/sshfs  683G  7.2G  641G   2% /mnt/tmpfs/sshfs

Это не сработает, поскольку sshfs сама создает новую точку монтирования. Так что предыдущая точка монтирования даже не имеет значения.

Я думаю, что (мог ошибаться ), что sshfs уже буферизует записи в ОЗУ, прежде чем отправить их. Извините, я не мог быть более полезным.

-1
10.02.2021, 19:21
1 ответ
#!/bin/sh

while read -r user
  do
    for group in users people
      do
        sed -nr "s/.*\[(\S+).*\s(uid=$user,ou=$group,.*)./$user|\1|\2/p" file*.txt | sort -t\| -k2.8nr -k2.4Mr -k2.1nr -k2.13,2.20r | grep -m1 "|uid=$user,ou=$group,"
    done
done < userid.txt

Редактировать:

если файлы журналов уже отсортированы, перебрать файлы для каждого DN и tail -n1. первый проход просканирует пользователей и создаст другой входной файл userdn.txtдля второго прохода

#!/bin/sh

# list of users (from logs)
grep -Fiwhf userid.txt file*.txt | grep -io 'uid=[^"]*' | sort --ignore-case -u > userdn.txt

# last login
while read -r user
  do
    grep -Fiwh "$user" file*.txt | tail -n1 | sed -nr 's/.*\[(\S+).*\suid=([^,]+)(.*)./\2|\1|uid=\2\3/p'
done < userdn.txt

или через замену процесса (только bash)

#!/bin/bash

while read -r user
  do
    grep -Fiwh "$user" file*.txt | tail -n1 | sed -nr 's/.*\[(\S+).*\suid=([^,]+)(.*)./\2|\1|uid=\2\3/p'
done < <(grep -Fiwhf userid.txt file*.txt | grep -io 'uid=[^"]*' | sort --ignore-case -u)

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

-создатьuserdn.txt
-сортировать файлы журналов по дате в один большой файл
-повторить bigfile.txtдля каждого DN

#!/bin/sh

# list of users (from logs)
grep -Fiwhf userid.txt file*.txt | grep -io 'uid=[^"]*' | sort --ignore-case -u > userdn.txt

# merge log files
grep -Fiwhf userdn.txt file*.txt | sed -nr 's/.*\[(\S+).*\suid=([^,]+)(.*)./\2|\1|uid=\2\3/p' | sort -t\| -k2.8nr -k2.4Mr -k2.1nr -k2.13,2.20r > bigfile.txt

# last login
while read -r user
  do
    grep -Fiwm1 "$user" bigfile.txt
done < userdn.txt

Это по-прежнему не является хорошим решением, потому что в конце концов каждый журнал обрабатывается несколько раз для каждого пользователя. должно быть другое решение с awk, или join, или paste, или uniq, или что-то в этом роде.

В идеале я бы просто объединил...

tac file*.txt | grep -m1 -f userdn.txt

... но это не сработает по двум причинам:
tacРаботает не так, как ожидалось, вместо этого последовательно обрабатывается каждый журнал один за другим.
-m1в сочетании с -fне выполняет поиск всех шаблонов (из файла ), а останавливается после любого шаблона .
даже если это сработает только для уже отсортированных бревен:(


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

Эта функция должна:

-проверить, существует ли уже DN
-сравнить дату
-обновить существующую запись
-добавлять только новые записи

#!/bin/bash

shopt -s extglob

# function compare date
compare () {
  [ -n "$2" ] || return 1

  # sort array
  for date in "$@"
    do
      echo "$date"
  done | sort -k1.8n -k1.4M -k1.1n -k1.13,1.20 | tail -n1

  return 0
}

# function write last_login.txt
update () {
  local file=$1 line=$2
  [ -n "$line" ] || return 1

  # string manipulation
  dn=${line#*\"}; dn=${dn%%\"*}; dn=${dn#*+([[:blank:]])}; [ -n "$dn" ] || return 1
  user=${dn%%,*}; user=${user#*=};
  date2=${line#*[}; date2=${date2%%]*}; date2=${date2%+([[:blank:]])*};

  [ -f "$file" ] && date1=$(grep -Fiwm1 "$dn" "$file" | cut -d\| -f2)
  if [ -n "$date1" ]
    then
      # DN already exist
      [ "$date1" = "$date2" ] && return 0
      date=$(compare "$date1" "$date2")
      if [ "$date" != "$date1" ]
        then
          # update existing entry
          sed -i "s;$user|$date1|$dn;$user|$date2|$dn;i" "$file"
      fi
    else
      # add new entries only
      echo "$user|$date2|$dn" >> "$file"
  fi

  return 0
}

# create last_login.txt
for file in file*.txt
  do
    [ -f "$file" ] || continue
    echo "processing $file"
    while read -r line
      do
        update last_login.txt "${line//;/,}"
    done < <(tac "$file")
done

# sort last_login.txt
echo -n "sorting... "
sort -o last_login.txt last_login.txt
echo "finished"

exit 0
1
18.03.2021, 22:32

Теги

Похожие вопросы