Làm cách nào tôi có thể khiến tập lệnh đăng nhập vào một tệp riêng biệt số lần nó được thực thi?


11

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:


15

Tôi giả sử bạn muốn có một tệp countfileduy 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, $counterví 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 countfilechư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

2
Hay hoặc như thế này:echo $(( $(cat countfile 2>/dev/null || echo 0) + 1 )) > countfile
PerlDuck

1
Thật tuyệt, điều đó dường như cũng hoạt động tốt @PerlDuck. Tôi sợ rằng nó có thể mở tệp để ghi đè trước khi đọc, nhưng rõ ràng cú pháp thay thế quy trình dường như ngăn chặn điều đó.
Chỉ huy Byte

Điểm tốt. Tôi không hoàn toàn chắc chắn liệu nó có đảm bảo $(…)đượ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.
PerlDuck

2
Câu trả lời này sẽ được cải thiện bằng cách gói mã đó trong một flocklệnh để ngăn chặn điều kiện cuộc đua. Xem unix.stackexchange.com/a/409276
rrauenza

5

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:SSlà đị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

5

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

  1. nhân đôi luồng lỗi tiêu chuẩn (2) sang một bộ mô tả tệp khác (3),
  2. thay thế nó (2) bằng một chuyển hướng đến /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 readlệnh nếu dự kiến ​​thiếu tệp truy cập),
  3. sau đó nhân đôi luồng lỗi tiêu chuẩn ban đầu (bây giờ là 3) trở lại vị trí (2) và
  4. đóng bản sao của luồng lỗi tiêu chuẩn (3).

1

Một cách tiếp cận khác

Một tập tin truy cập riêng biệt có nhược điểm:

  • Phải mất 4096 byte (hoặc bất kể kích thước khối của bạn) cho mỗi tệp truy cập.
  • Bạn phải tra cứu tên của tệp trong tập lệnh bash và sau đó mở tệp để xem số đếm.
  • Không có khóa tệp (trong các câu trả lời khác) vì vậy có thể hai người cập nhật bộ đếm cùng một lúc (được gọi là điều kiện cuộc đua trong các nhận xét theo câu trả lời của Byte Commander).

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!

  • Đặt bộ đếm vào chính tập lệnh bash cho phép bạn nhìn thấy trong chính tập lệnh của mình bao nhiêu lần nó đã được chạy.
  • Sử dụng 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.
  • Vì tên tệp truy cập không được mã hóa cứng, bạn không cần thay đổi mã cho các tập lệnh khác nhau, bạn có thể chỉ cần lấy nguồn hoặc sao chép và dán từ tệp sơ khai / soạn sẵn.

Mật mã

#!/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

Cách tiếp cận khác bằng cách sử dụng tệp nhật ký

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 gedithoặc nautilus.

Mặc dù vậy, việc nắm bắt hơn là sử dụng gksutập lệnh được đặt tên gsuvà gọi pkexeccá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 geditmà 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-geditsau 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"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.