Мені потрібно написати сценарій, який записує у файл, скільки разів цей сценарій був виконаний.
Як я можу це зробити?
Мені потрібно написати сценарій, який записує у файл, скільки разів цей сценарій був виконаний.
Як я можу це зробити?
Відповіді:
Я припускаю, що ви хочете мати один файл, countfileякий містить лише одне єдине число, що представляє лічильник виконання.
Ви можете прочитати цей лічильник у змінній оболонки, $counterнаприклад, використовуючи один із цих рядків:
read counter < countfilecounter=$(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
$(…)він виконаний раніше, ніж будь-що інше (особливо перед >). Але я часто використовую $(cat countfile 2>/dev/null || echo 0)частину, щоб отримати розумний типовий випадок, якщо файл не існує. Ми можемо додати sponge:-), щоб бути безпечним.
flockкомандою, щоб запобігти умовам перегонів. Дивіться unix.stackexchange.com/a/409276
Просто дозвольте скрипту створити файл журналу, додайте, наприклад, рядок у своєму сценарії наприкінці:
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
Це рішення використовує той самий підхід, що і у відповіді командира байта, але воно не покладається на арифметику оболонки або інші башизми.
exec 2>&3 2>/dev/null
read counter < counter.txt || counter=0
exec 3>&2 3>&-
expr "$counter" + 1 > counter.txt
Перенаправлення потоку
/dev/null(щоб придушити повідомлення про помилку при наступному перенаправлення вводу readкоманди, якщо файл лічильника очікувано відсутній),Окремий файл лічильника має недоліки:
Тож ця відповідь усуває окремий лічильник файлів і ставить рахунок у сам скрипт bash!
flockгарантує, що на короткий момент двоє користувачів не можуть одночасно запускати сценарій.#!/bin/bash
# NAME: run-count.sh
# PATH: $HOME/bin
# DESC: Written for AU Q&A: /ubuntu/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 для підтримання аудиту / журналу файлів, для доступу до журналу щоразу, коли використовувались повноваження root geditабо nautilus.
Хоча улов, а не використання gksuсценарію, називається gsuі викликає pkexec"сучасний" спосіб використання sudo в графічному інтерфейсі, тому мені кажуть.
Ще одна перевага полягає не лише в тому, що він говорить щоразу, коли використовуються повноваження root, 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"
echo $(( $(cat countfile 2>/dev/null || echo 0) + 1 )) > countfile