如何使脚本在单独的文件中记录它执行的次数?

我需要编写一个脚本来写一个文件这个脚本执行了多少次。

我怎样才能做到这一点?

我假设你想拥有一个文件countfile ,它只包含一个代表执行计数器的数字。

您可以将此计数器读入shell变量$counter例如使用以下行之一:

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

可以使用$(( EXPRESSION ))语法在Bash中完成简单的整数添加。 然后简单地将结果写回我们的countfile

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

你应该也可以保护你的脚本,因为countfile还不存在,然后用值1创建一个初始值。

整件事情看起来像这样:

 #!/bin/bash if [[ -f countfile ]] ; then read counter < countfile else counter=0 fi echo "$(( counter + 1 ))" > countfile 

只需让脚本创建一个日志文件,最后在脚本中添加一行代码:

 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 

此解决方案使用与Byte Commander的答案相同的方法,但它不依赖于shell算法或其他Bashisms。

 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)。

一种不同的方法

单独的计数器文件有缺点:

  • 每个计数器文件需要4096个字节(或任何块大小)。
  • 您必须在bash脚本中查找文件的名称,然后打开该文件以查看计数。
  • 没有文件锁定(在其他答案中),因此两个人可能在同一时间更新计数器(在Byte Commander的答案中称为竞争条件)。

所以这个答案取消了一个单独的计数器文件并将计数放入bash脚本本身!

  • 将计数器放在bash脚本本身允许您在脚本中查看它运行了多少次。
  • 使用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脚本,用于维护每次root权限与geditnautilus一起使用时访问的文件的审计跟踪/日志 。

虽然捕获的不是使用gksu脚本命名为gsugsu调用pkexec在GUI中使用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"