Tôi cần phải viết một tập lệnh ghi vào một tập tin bao nhiêu lần tập lệnh này đã được thực thi.
Làm thế nào tôi có thể làm điều đó?
Tôi cần phải viết một tập lệnh ghi vào một tập tin bao nhiêu lần tập lệnh này đã được thực thi.
Làm thế nào tôi có thể làm điều đó?
Câu trả lời:
Tôi giả sử bạn muốn có một tệp countfile
duy nhất chỉ chứa một số duy nhất đại diện cho bộ đếm thực thi.
Bạn có thể đọc bộ đếm này thành một biến shell, $counter
ví dụ như sử dụng một trong những dòng sau:
read counter < countfile
counter=$(cat countfile)
Bổ sung số nguyên đơn giản có thể được thực hiện trong chính Bash bằng $(( EXPRESSION ))
cú pháp. Sau đó, chỉ cần viết kết quả lại cho chúng tôi countfile
:
echo "$(( counter + 1 ))" > countfile
Có lẽ bạn cũng nên bảo vệ tập lệnh của mình cho trường hợp countfile
chưa tồn tại và tạo tập lệnh khởi tạo với giá trị 1 sau đó.
Toàn bộ điều này có thể trông như thế này:
#!/bin/bash
if [[ -f countfile ]] ; then
read counter < countfile
else
counter=0
fi
echo "$(( counter + 1 ))" > countfile
$(…)
được thực hiện trước bất kỳ điều gì khác hay không (đặc biệt là trước >
). Nhưng tôi thường sử dụng $(cat countfile 2>/dev/null || echo 0)
một phần để có được một mặc định hợp lý trong trường hợp tập tin không tồn tại. Chúng tôi có thể thêm một sponge
:-) để được an toàn.
flock
lệnh để ngăn chặn điều kiện cuộc đua. Xem unix.stackexchange.com/a/409276
Chỉ cần để tập lệnh tạo tệp nhật ký, thêm ví dụ một dòng trong tập lệnh của bạn ở cuối:
echo "Script has been executed at $(date +\%Y-\%m-\%d) $(date +\%H-\%M-\%S)" >> ~/script.log
Bằng cách này, bạn có thể tự định dạng cách bạn trình bày ngày và giờ, nhưng nếu bạn chỉ muốn đi với đầy đủ ngày và giờ (và HH:MM:SS
là định dạng có thể chấp nhận cho bạn), bạn cũng có thể sử dụng một cách đơn giản:
echo "Script has been executed at $(date +\%F-\%T)" >> ~/script.log
Sau đó, bạn có thể làm:
wc -l ~/script.log
Việc đếm các ký tự dòng mới và đưa ra ước tính có bao nhiêu dòng bên trong tệp nhật ký. Lên đến mức bạn có thể thấy trong tệp nhật ký ngay cả khi nó được thực thi. Để điều chỉnh nó theo nhu cầu của bạn, bạn có thể thay đổi đường dẫn và tên được sử dụng để đăng nhập. Tôi vừa làm một ví dụ ở đây để lưu logfile ~
.
Vì vậy, ví dụ bạn muốn tập lệnh thêm số này vào dòng bạn đã thêm vào cuối tập lệnh, bạn có thể làm một cái gì đó như thế này khi bắt đầu tập lệnh của bạn:
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"
Và thay đổi dòng của bạn ở cuối tập lệnh thành một cái gì đó bao gồm cả thông tin đó:
echo "Script has been executed $count times at $(date +\%F-\%T)" >> ~/script.log
Giải pháp này sử dụng cách tiếp cận tương tự như câu trả lời của Byte Commander nhưng nó không dựa vào số học shell hay Bashism khác.
exec 2>&3 2>/dev/null
read counter < counter.txt || counter=0
exec 3>&2 3>&-
expr "$counter" + 1 > counter.txt
Các luồng chuyển hướng
/dev/null
(để chặn thông báo lỗi trong lần chuyển hướng tiếp theo của đầu vào của read
lệnh nếu dự kiến thiếu tệp truy cập),Một tập tin truy cập riêng biệt có nhược điểm:
Vì vậy, câu trả lời này không có một tập tin truy cập riêng biệt và đặt số đếm vào chính tập lệnh bash!
flock
đảm bảo rằng trong một thời gian ngắn, hai người dùng không thể chạy tập lệnh cùng một lúc.#!/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
Tương tự như câu trả lời của Videonauth, tôi đã viết một câu trả lời tệp nhật ký ở đây: Tập lệnh Bash để duy trì đường dẫn kiểm toán / nhật ký của các tệp được truy cập để ghi nhật ký mỗi khi quyền hạn gốc được sử dụng với gedit
hoặc nautilus
.
Mặc dù vậy, việc nắm bắt hơn là sử dụng gksu
tập lệnh được đặt tên gsu
và gọi pkexec
cách sử dụng sudo "hiện đại" trong GUI, vì vậy tôi được cho biết.
Một ưu điểm khác là nó không chỉ cho biết mỗi lần quyền hạn gốc được sử dụng gedit
mà còn ghi lại tên tệp đã được chỉnh sửa. Đây là mã.
~/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
Nội dung của tệp nhật ký gsu-log-file-for-gedit
sau một vài chỉnh sửa:
__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