ฉันจะทำให้สคริปต์เข้าสู่ระบบไฟล์แยกจำนวนครั้งที่ถูกดำเนินการได้อย่างไร


11

ฉันต้องเขียนสคริปต์ที่เขียนไปยังไฟล์กี่ครั้งที่สคริปต์นี้ได้รับการดำเนินการ

ฉันจะทำสิ่งนั้นได้อย่างไร

คำตอบ:


15

ฉันคิดว่าคุณต้องการมีไฟล์เดียว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

2
…หรือเป็นเช่นนี้:echo $(( $(cat countfile 2>/dev/null || echo 0) + 1 )) > countfile
PerlDuck

1
ดีที่ดูเหมือนว่าจะทำงานได้ดี @PerlDuck ฉันกลัวว่ามันอาจเปิดไฟล์เพื่อเขียนทับก่อนที่จะอ่าน แต่ดูเหมือนว่าไวยากรณ์การแทนที่กระบวนการดูเหมือนจะป้องกันไม่ให้เกิดขึ้น
ผู้บัญชาการ Byte

จุดดี. ฉันไม่แน่ใจว่าจะรับประกัน$(…)ได้หรือไม่ว่าจะถูกดำเนินการก่อนสิ่งอื่นใด (โดยเฉพาะก่อนหน้านี้>) แต่ฉันมักจะใช้ชิ้น$(cat countfile 2>/dev/null || echo 0)ส่วนเพื่อรับค่าเริ่มต้นที่เหมาะสมในกรณีที่ไม่มีไฟล์ เราสามารถเพิ่มsponge:-) เพื่อความปลอดภัย
PerlDuck

2
คำตอบนี้จะได้รับการปรับปรุงโดยการห่อรหัสการนับในflockคำสั่งเพื่อป้องกันสภาวะการแข่งขัน ดูunix.stackexchange.com/a/409276
rrauenza

5

เพียงแค่ให้สคริปต์สร้างไฟล์บันทึกเพิ่มตัวอย่างเช่นบรรทัดในสคริปต์ของคุณในตอนท้าย:

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

ซึ่งนับอักขระขึ้นบรรทัดใหม่และให้การประมาณจำนวนบรรทัดที่อยู่ในไฟล์บันทึก จนถึงที่คุณสามารถดูได้ในล็อกไฟล์แม้ว่าจะถูกเรียกใช้งานแล้วก็ตาม เพื่อปรับให้เข้ากับความต้องการของคุณคุณสามารถเปลี่ยนเส้นทางและชื่อที่ใช้สำหรับการบันทึก ผมก็ไม่ได้ตัวอย่างที่นี่ซึ่งจะช่วยประหยัด logfile ~ใน

ตัวอย่างเช่นคุณต้องการให้สคริปต์เพิ่มจำนวนนี้ไปยังบรรทัดที่คุณเพิ่มในตอนท้ายของสคริปต์คุณสามารถทำสิ่งนี้ในตอนเริ่มต้นสคริปต์ของคุณ:

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

วิธีนี้ใช้วิธีการเดียวกับคำตอบของผู้บัญชาการ Byteแต่ไม่ได้ใช้เลขคณิตของเชลล์หรือ Bashisms อื่น ๆ

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

การเปลี่ยนเส้นทางกระแส

  1. ทำซ้ำสตรีมข้อผิดพลาดมาตรฐาน (2) ไปที่ file descriptor อื่น (3)
  2. แทนที่ (2) ด้วยการเปลี่ยนเส้นทางไปที่/dev/null(เพื่อระงับข้อความแสดงข้อผิดพลาดในการเปลี่ยนเส้นทางที่ตามมาของอินพุตของreadคำสั่งหากไฟล์ตัวนับหายไปโดยไม่คาดหมาย)
  3. ต่อมาทำซ้ำสตรีมข้อผิดพลาดมาตรฐานดั้งเดิม (ตอนนี้ที่ 3) กลับเข้าที่ (2) และ
  4. ปิดสำเนาของสตรีมข้อผิดพลาดมาตรฐาน (3)

1

แนวทางที่แตกต่าง

ไฟล์ตัวนับแยกมีข้อเสีย:

  • ใช้เวลา 4096 ไบต์ (หรือขนาดบล็อกของคุณ) สำหรับไฟล์ตัวนับแต่ละไฟล์
  • คุณต้องค้นหาชื่อไฟล์ในสคริปต์ทุบตีแล้วเปิดไฟล์เพื่อดูจำนวน
  • ไม่มีการล็อกไฟล์ (ในคำตอบอื่น ๆ ) ดังนั้นจึงเป็นไปได้ที่คนสองคนจะอัพเดตตัวนับในเวลาเดียวกัน (เรียกว่าสภาพการแข่งขันในความคิดเห็นภายใต้คำตอบของผู้บัญชาการของ Byte)

ดังนั้นคำตอบนี้ไปด้วยตัวนับไฟล์แยกต่างหากและทำให้จำนวนในสคริปต์ทุบตีตัวเอง!

  • การวางตัวนับในสคริปต์ทุบตีจะช่วยให้คุณเห็นตัวสคริปต์ของคุณเองว่ามีการรันกี่ครั้ง
  • การใช้การflockรับรองว่าช่วงเวลาสั้น ๆ เป็นไปไม่ได้ที่ผู้ใช้สองคนจะเรียกใช้สคริปต์ในเวลาเดียวกัน
  • เนื่องจากชื่อไฟล์ตัวนับไม่ได้เข้ารหัสยากคุณไม่จำเป็นต้องเปลี่ยนรหัสสำหรับสคริปต์ที่แตกต่างกันคุณเพียงแค่สามารถหาแหล่งที่มาหรือคัดลอกและวางจากไฟล์ stub / สำเร็จรูป

รหัส

#!/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 ผมเขียนคำตอบที่ล็อกไฟล์ที่นี่: ทุบตีสคริปต์เพื่อรักษาเส้นทางการตรวจสอบ / log ของไฟล์ที่เข้าถึงได้เข้าสู่ระบบเวลาอำนาจรากถูกนำมาใช้กับทุกคนหรือgeditnautilus

แม้ว่าการดักจับไม่ใช่การใช้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"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.