Как я могу заставить скрипт войти в отдельный файл столько раз, сколько он был выполнен?

Мне нужно написать скрипт, который записывает в файл, сколько раз этот скрипт был выполнен.

Как я могу это сделать?

10
задан 20 December 2017 в 17:01

4 ответа

Я предполагаю, что вы хотите иметь один файл countfile, который содержит только одно число, представляющее счетчик выполнения.

Вы можете считать этот счетчик в переменную оболочки $counter, например. используя одну из этих строк:

  • read counter < countfile
    
  • counter=$(cat countfile)
    

Простые целочисленные добавления могут быть сделаны в самом Bash с помощью $(( EXPRESSION )) синтаксис. Затем просто запишите результат обратно в наш countfile:

echo "$(( counter + 1 ))" > countfile

Вы, вероятно, также должны защитить свой сценарий на случай, что countfile еще не существует, и затем создать его, инициализированный со значением 1.

Все это может выглядеть так:

#!/bin/bash
if [[ -f countfile ]] ; then
    read counter < countfile
else
    counter=0
fi
echo "$(( counter + 1 ))" > countfile
14
ответ дан 20 December 2017 в 17:01

В этом решении используется тот же подход, что и в ответе Byte Commander , но оно не опирается на арифметику оболочек или другие ошибки.

exec 2>&3 2>/dev/null
read counter < counter.txt || counter=0
exec 3>&2 3>&-
expr "$counter" + 1 > counter.txt

Перенаправления потока

  1. дублируют стандартный поток ошибок (2) в другой файловый дескриптор (3),
  2. заменяют его (2) перенаправлением на /dev/null (для подавления сообщения об ошибке при последующем перенаправлении ввода команды read, если файл счетчика ожидаемо отсутствует),
  3. позже дублируют исходный стандартный поток ошибок (теперь на 3) назад на место (2) и
  4. закройте копию стандартного потока ошибок (3).
5
ответ дан 20 December 2017 в 17:01

Просто позвольте сценарию создать файл журнала, добавьте, например, строку в своем сценарии в конце:

echo "Script has been executed at $(date +\%Y-\%m-\%d) $(date +\%H-\%M-\%S)" >> ~/script.log

Таким образом, вы можете отформатировать способ представления даты и времени самостоятельно, но если вы просто хотите указать полную дату и время (и HH:MM:SS является приемлемым форматом для вас), вы также можете просто использовать:

echo "Script has been executed at $(date +\%F-\%T)" >> ~/script.log

Тогда вы можете сделать:

wc -l ~/script.log

, который подсчитывает символы новой строки и дает вам оценку количества строк в файле журнала. До этого вы можете видеть в файле журнала, даже когда он был выполнен. Чтобы адаптировать его к вашим потребностям, вы можете изменить пути и имена, используемые для регистрации. Я только что сделал пример, который сохраняет файл журнала в ~.

Так, например, вы хотите, чтобы скрипт добавил это количество к строке, которую вы добавили в конце вашего скрипта, вы можете сделать что-то вроде этого в начале вашего скрипта:

count=$(( $(wc -l ~/script.log | awk '{print $1}') + 1 ))
# the next line can be simply skipped if you not want an output to std_out
echo "Script execution number: $count"

И изменить свою строку в конце сценария к чему-то, включая даже эту информацию:

echo "Script has been executed $count times at $(date +\%F-\%T)" >> ~/script.log
5
ответ дан 20 December 2017 в 17:01

Другой подход

Отдельный встречный файл имеет недостатки:

  • Требуется 4 096 байтов (или независимо от того, что Ваш размер блока) для каждого встречного файла.
  • Необходимо искать название файла в сценарии удара и затем открыть файл для наблюдения количества.
  • Нет никакого захвата файла (в других ответах), таким образом, возможно, что два человека обновляют счетчик в то же самое время (названный состоянием состязания в комментариях в соответствии с ответом Командующего Байта).

Таким образом, этот ответ покончил с отдельным встречным файлом и помещает количество в сам сценарий удара!

  • Помещение счетчика в самом сценарии удара позволяет Вам видеть в рамках Вашего сценария самого, сколько раз это было выполнено.
  • Используя flock гарантии, что в течение краткого момента для двух пользователей не возможно запустить скрипт одновременно.
  • Поскольку встречное имя файла трудно не кодируется, Вы не должны изменять код для различных сценариев, можно просто получить его или скопировать и вставить его от тупика / шаблонный файл.

Код

#!/bin/bash

# NAME: run-count.sh
# PATH: $HOME/bin
# DESC: Written for AU Q&A: https://askubuntu.com/questions/988032/how-can-i-cause-a-script-to-log-in-a-separate-file-the-number-of-times-it-has-be

# DATE: Mar 16, 2018.

# This script run count: 0

# ======== FROM HERE DOWN CAN GO INTO FILE INCLUDED WITH SOURCE COMMAND =======

[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :
#     This is useful boilerplate code for shell scripts.  Put it at the top  of
#     the  shell script you want to lock and it'll automatically lock itself on
#     the first run.  If the env var $FLOCKER is not set to  the  shell  script
#     that  is being run, then execute flock and grab an exclusive non-blocking
#     lock (using the script itself as the lock file) before re-execing  itself
#     with  the right arguments.  It also sets the FLOCKER env var to the right
#     value so it doesn't run again.

# Read this script with entries separated newline " " into array
mapfile -t ScriptArr < "$0"

# Build search string that cannot be named
SearchStr="This script"
SearchStr=$SearchStr" run count: "

# Find our search string in array and increment count
for i in ${!ScriptArr[@]}; do
    if [[ ${ScriptArr[i]} = *"$SearchStr"* ]]; then
        OldCnt=$( echo ${ScriptArr[i]} | cut -d':' -f2 )
        NewCnt=$(( $OldCnt + 1 ))
        ScriptArr[i]=$SearchStr$NewCnt
        break
    fi
done

# Rewrite our script to disk with new run count
# BONUS: Date of script after writing will be last run time
printf "%s\n" "${ScriptArr[@]}" > "$0"

# ========= FROM HERE UP CAN GO INTO FILE INCLUDED WITH SOURCE COMMAND ========

# Now we return you to your original programming....

exit 0

Другой Подход с помощью Файла журнала

Подобный ответу Videonauth я записал ответ файла журнала здесь: сценарий Bash для поддержания журнала аудита / журнал файлов получил доступ для входа каждый раз, когда корневые полномочия использовались с gedit или nautilus.

Выгода, хотя вместо использования gksu сценарий называют gsu и вызывает pkexec "современный" способ использовать sudo в GUI, таким образом, мне говорят.

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

~/bin/gsu:

#!/bin/bash

# Usage: gsu gedit file1 file2...
#  -OR-  gsu natuilus /dirname

# & is used to spawn process and get prompt back ASAP
# > /dev/null is used to send gtk warnings into dumpster

COMMAND="$1" # extract gedit or nautilus

pkexec "$COMMAND" "${@:2}"

log-file "${@:2}" gsu-log-file-for-"$COMMAND"

/usr/local/bin/log-file:

#! /bin/bash

# NAME: log-file
# PATH: /usr/local/bin
# DESC: Update audit trail/log file with passed parameters.
# CALL: log-file FileName LogFileName
# DATE: Created Nov 18, 2016.
# NOTE: Primarily called from ~/bin/gsu

ABSOLUTE_NAME=$(realpath "$1")
TIME_STAMP=$(date +"%D - %T")
LOG_FILE="$2"

# Does log file need to be created?
if [ ! -f "$LOG_FILE" ]; then
    touch "$LOG_FILE"
    echo "__Date__ - __Time__ - ______File Name______" >> "$LOG_FILE"
    #     MM/DD/YY - hh:mm:ss - "a/b/c/FileName"
fi

echo "$TIME_STAMP" - '"'"$ABSOLUTE_NAME"'"' >> "$LOG_FILE"

exit 0

Содержание файла журнала gsu-log-file-for-geditпосле нескольких редактирований:

__Date__ - __Time__ - ______File Name______
11/18/16 - 19:07:54 - "/etc/default/grub"
11/18/16 - 19:08:34 - "/home/rick/bin/gsu"
11/18/16 - 19:09:26 - "/home/rick/bin/gsu"
1
ответ дан 20 December 2017 в 17:01

Другие вопросы по тегам:

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