스크립트가 실행 된 횟수만큼 별도의 파일에 로그인하도록하려면 어떻게해야합니까?


답변:


15

countfile실행 카운터를 나타내는 하나의 단일 숫자 만 포함 하는 단일 파일 을 원한다고 가정합니다 .

이 카운터를 쉘 변수로 읽을 수 있습니다 ( $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

2
… 또는 이것처럼 :echo $(( $(cat countfile 2>/dev/null || echo 0) + 1 )) > countfile
PerlDuck

1
니스, @PerlDuck도 잘 작동하는 것 같습니다. 파일이 읽히기 전에 덮어 쓰기 위해 파일을 열지 않을까 두려워했지만 분명히 프로세스 대체 구문이이를 방지하는 것으로 보입니다.
바이트 사령관

좋은 지적. $(…)다른 어떤 것보다 (특히) 전에 실행되는 것이 보장되는지 확실하지 않습니다 >. 그러나 $(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

개행 문자를 계산하고 로그 파일에 몇 줄이 있는지 추정합니다. 그것까지는 로그 파일이 실행될 때조차 볼 수 있습니다. 필요에 맞게 조정하기 위해 로깅에 사용되는 경로와 이름을 변경할 수 있습니다. 방금 로그 파일을에 저장하는 예를 보았습니다 ~.

예를 들어 스크립트 끝에 스크립트에 추가 한 줄에이 개수를 추가하려면 스크립트 시작시 다음과 같이 할 수 있습니다.

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 Commander의 답변 과 동일한 접근 방식을 사용 하지만 쉘 산술 또는 다른 Bashism에 의존하지 않습니다.

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. 카운터 파일이 예상치 못한 경우 명령 /dev/null입력의 후속 경로 재 지정에서 오류 메시지를 표시하지 않으려면 (2)를 경로 재 지정으로 바꾸십시오 read.
  3. 나중에 원래 표준 오류 스트림 (현재 3)을 다시 제자리에 복제합니다 (2).
  4. 표준 오류 스트림 (3)의 사본을 닫습니다.

1

다른 접근법

별도의 카운터 파일에는 다음과 같은 단점이 있습니다.

  • 각 카운터 파일에 4096 바이트 (또는 블록 크기에 관계없이)가 필요합니다.
  • bash 스크립트에서 파일 이름을 찾은 다음 파일을 열어 개수를 확인해야합니다.
  • 파일 잠금 (다른 답변에서는)이 없으므로 두 사람이 동시에 카운터를 업데이트 할 수 있습니다 (Byte Commander의 답변 아래 주석에서 경쟁 조건이라고 함).

따라서이 답변은 별도의 카운터 파일을 없애고 bash 스크립트 자체에 카운트를 넣습니다!

  • 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 스크립트 .geditnautilus

그러나 catch gksu는 스크립트를 사용 하는 것이 아니라 GUI에서 sudo를 사용하는 "현대적인"방식을 gsu호출 pkexec하므로 이름을 듣습니다.

또 다른 장점은 루트 전원을 사용할 때마다 말할 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.