Bashを使用して上書きせずにログファイルのバッチの名前を徐々に変更するには?

Bashを使用して上書きせずにログファイルのバッチの名前を徐々に変更するには?

私のソリューションは初期テストケースに合格しましたが、送信時に50%の時間に失敗する問題が発生しました。

問題:ディレクトリには複数のファイルとフォルダが含まれており、その中にはerror.log、error.log.1、error.log.2、access.log.1、access.log.2などのさまざまな種類があります。ログです。 。このファイルの内容は翌日にマッピングされるため、「cat error.log.1」には「Next Day Log」..etcがあります。

タスクは、ログの末尾にある数字だけを増やし、ディレクトリの残りの部分は変更せずに残すことです。また、ログタイプごとに空のファイルを作成します。

たとえば、

./
example_dir
example2_dir
error.log
error.log.1
info.log.20
access.log.1
readme.txt

スクリプトはディレクトリを次に変更します。

./
example_dir (unchanged)
example2_dir (unchanged)
error.log (empty)
error.log.1 (originally error.log)
error.log.2 (originally error.log.1)
info.log (empty)
info.log.21 (originally info.log.20)
access.log (empty)
access.log.2 (originally access.log.1)
readme.txt (unchanged)

条件:#ディレクトリのファイル< 1000、各タイプの最大#ファイル< 21

私の解決策:

#!/bin/bash

declare -a filenames

# Renaming in ascending order will lead to overwrite; so start rename from the bottom

files=$(find . -maxdepth 1 -name "*.log.*" -exec basename {} \; | sort -rn)


for i in $files; do

    currentFileNumber=$(echo -e "$i" | sed -e 's/[^0-9]*//g') # Extract the current number from the filename
    fileName=$(echo -e "$i" | sed -e 's/\.[0-9]*$//g') # Extract the name without the trailing number

    newFileNumber=$(("$currentFileNumber" + 1)) # Increment the current number

    mv "$i" "$fileName.$newFileNumber" # Rename and append the incremented value

    if [[ ! ${filenames[*]} =~ ${fileName} ]] # Store names of existing types to create empty files
    then
        filenames=("${filenames[@]}" "${fileName}")
    fi
    # Could make use of [[ -e "$fileName.log" ]] instead of an array, but won't pass the test for some reason
done

for j in "${filenames[@]}"; do touch "$j"; done # Create the empty files
unset filenames

失敗したテストケースが表示されないため、この問題をよりよく解決する方法がわかりません。

ベストアンサー1

これは楽しい練習だったし、ここに私の解決策があります。

#/bin/bash
log_names=$(for logfile in $(find . -type f -name '*.log*'); do echo ${logfile%.[0-9]*}; done | sort -u)

for name in $log_names; do
    echo "Processing $name"
    i=20
    until [[ "$i" -eq 0 ]]; do
        if [[ -f "$name.$i" ]]; then
            next_num=$((i+1))
            mv -v "$name.$i" "$name.$next_num"
        fi
        i=$((i-1))
    done
    if [[ -f "$name" ]]; then
        mv -v "$name" "$name.1"
    fi
    touch "$name"
done

log_names変数は、findコマンドを使用してログファイルのリストを取得します。次に、文字列置換を適用して数値サフィックスを削除します。次に、重複した項目をソートして削除します。

この時点で、次のディレクトリに一意のログファイル名のリストが表示されます./access.log ./error.log ./info.log

その後、ループを使用して各名前を順番に処理しますfor

これで、各ファイルの最大数は20個と聞きました。ここから始めて、untilループを使ってカウントダウンします。

ロジックはmv簡単です。 「filname.number」がある場合は、「filename.(number+1)」に移動します。

ループが完了するとuntil(i = 0)、数字のサフィックスを持たない非回転ファイルが残ることがあります。その場合は、filename.1にアクセスしてください。

最後のステップは空のファイルを作成することですtouch


実行例:

$ ls
access.log.1  error.log  error.log.1  example_dir  example2_dir  info.log.20  readme.txt  rotate.bash
    
$ bash rotate.bash
Processing ./access.log
'./access.log.1' -> './access.log.2'
Processing ./error.log
'./error.log.1' -> './error.log.2'
'./error.log' -> './error.log.1'
Processing ./info.log
'./info.log.20' -> './info.log.21'

$ ls -1
access.log
access.log.2
error.log
error.log.1
error.log.2
example_dir
example2_dir
info.log
info.log.21
readme.txt
rotate.bash

おすすめ記事