このスクリプトが遅く実行されるのはなぜですか?

このスクリプトが遅く実行されるのはなぜですか?

OpenMediaVaultでcronjobとして実行される次のbashスクリプトがあります。

BACKUP_DIR='/srv/dev-disk-by-uuid-9EE055CFE055ADF1/Backup dir/'
BACKUP_FILE_PATH="/srv/dev-disk-by-uuid-9EE055CFE055ADF1/Backup dir/Backup [ashen] ($(date +%d-%m-%Y)).tar.gz"
SERVER_DIR=/var/lib/docker/volumes/49c9e5c53ea5b9c893c0a80117860da9b493484395c0$
MAX_BACKUPS_COUNT=4

tar -zcf "$BACKUP_FILE_PATH" $SERVER_DIR

cd "$BACKUP_DIR"

[[ $( ls | wc -l ) -gt $MAX_BACKUPS_COUNT ]] && rm "$(ls -t | tail -1)"

このスクリプトのポイントは、指定された場所に.tar.gzバックアップを作成し、バックアップディレクトリに4つ以上のファイルがある場合は、最も古いファイルを削除することです(最も最近のバックアップは4つだけを維持することが重要です)。最後の行/コマンドが常に機能するわけではありません。端末で手動で実行すると期待どおりに機能し、時にはスクリプトが実行されますが、時にはスクリプト/行を手動で実行しようとするまで停止し、しばらくの間魔法のようにそれ自体が変更されるように見えます。

時々最後の行の実行が中断される理由を知っている人はいますか?バックアップが作成されたことを確認しましたが、同様です。

ベストアンサー1

ファイル名に改行文字が含まれていると、スクリプトは失敗します。解析lsとても悪い考えそして失敗する可能性が高いです。また、スクリプトは最新のファイルのみを削除します。したがって、100個のファイルがあれば99個が残ります。最後の4つのファイルを除いてすべてが削除されると予想しているようですが、スクリプトのロジックはそうではありません。

以下は、ランダムなファイル名を処理し、実際に最新の4つのファイルを除くすべてのファイルを削除する代替方法です。

#!/bin/bash

## avoid using CAPS for local variable names in shell scripts
backup_dir='/srv/dev-disk-by-uuid-9EE055CFE055ADF1/Backup dir/'
backup_file_path="/srv/dev-disk-by-uuid-9EE055CFE055ADF1/Backup dir/Backup [ashen] ($(date +%d-%m-%Y)).tar.gz"
server_dir='/var/lib/docker/volumes/49c9e5c53ea5b9c893c0a80117860da9b493484395c0$'
## This needs to be set to the number of files you want to keep plus one,
## so that we can use tail -n $max_backups below.
max_backups=5

tar -zcf "$BACKUP_FILE_PATH" "$SERVER_DIR" 

## delete all but the newest 4 tar.gz files in the
## backup directory
stat --printf '%Y %n\0' "$backup_dir"/*tar.gz |
  sort -rznk1,1 | tail -z -n +"$max_backups" |
  sed -z 's/^[0-9]* //' | xargs -0 rm -v

ここでの作業は、statこのコマンドとさまざまなダウンストリームパイプラインを介して行われます。コマンドが実行する操作の詳細な説明は次のとおりです。

  • stat --printf '%Y %n\0' "$backup_dir"/*tar.gz.tar.gz:バックアップディレクトリにあるすべてのファイルのepoch以降のファイル名とファイル寿命(秒)を印刷します。改行()でファイル名を処理するには、各エントリをNULL()で終了する\n必要があります。\0出力は次のとおりです。

    $ stat --printf '%Y %n\0' * | tr '\0' '\n'
    1616867929 ./afile 5  tar.gz
    1616868565 ./file 10  tar.gz
    1616868560 ./file 1  tar.gz
    1616868561 ./file 2  tar.gz
    1616867927 ./file 3  tar.gz
    1616867928 ./file 4  tar.gz
    1616867930 ./file 6  tar.gz
    1616868562 ./file 7  tar.gz
    1616868563 ./file 8  tar.gz
    1616868564 ./file 9  tar.gz
    

この例では読みやすく出力をパイピングしtr '\0' '\n'ますが、実際の出力では各レコードの末尾に1つずつあります\0

  • sort -rznk1,1:上記の出力は、数字でソート()、逆順にソート()、レコード区切り文字として使用()され、ファイルの寿命である最初のフィールド()のみを考慮するパイプstatにリンクされます。sort-n-r\0-z-k1,1

    出力は次のとおりです。

      $ stat --printf '%Y %n\0' "$backup_dir"/*tar.gz | 
          sort -rznk1,1 | tr '\0' '\n'
      1616868565 ./file 10  tar.gz
      1616868564 ./file 9  tar.gz
      1616868563 ./file 8  tar.gz
      1616868562 ./file 7  tar.gz
      1616868561 ./file 2  tar.gz
      1616868560 ./file 1  tar.gz
      1616867930 ./file 6  tar.gz
      1616867929 ./afile 5  tar.gz
      1616867928 ./file 4  tar.gz
      1616867927 ./file 3  tar.gz
    
  • tail -z -n +"$max_backups":このコマンドはtail -n +XRecordから始まり、最後に指定したレコードを印刷しますX。ここに変数がXあるので、$max_backups保持するファイルの数に1を加えた値に変数を設定する必要があります。 null で終わるレコードを-z処理します。tail

    今すぐ削除するファイルのリストがありますが、ファイルの寿命もあるので削除する必要があります。

       $ stat --printf '%Y %n\0' "$backup_dir"/*tar.gz  | sort -rznk1,1       
          | tail -z -n +5 | tr '\0' '\n'
      1616868561 ./file 2  tar.gz
      1616868560 ./file 1  tar.gz
      1616867930 ./file 6  tar.gz
      1616867929 ./afile 5  tar.gz
      1616867928 ./file 4  tar.gz
      1616867927 ./file 3  tar.gz
    
  • sed -z 's/^[0-9]* //':ファイルの年齢を削除し、名前のみを保持します。今回も-znull で終わるレコードを処理します。

      $ stat --printf '%Y %n\0' "$backup_dir"/*tar.gz  | 
              sort -rznk1,1 | tail -z -n +5 | 
                  sed -z 's/^[0-9]* //' | tr '\0' '\n' 
      ./file 2  tar.gz
      ./file 1  tar.gz
      ./file 6  tar.gz
      ./afile 5  tar.gz
      ./file 4  tar.gz
      ./file 3  tar.gz
    
  • xargs -0 rm -v:最後のステップ。これによりファイルが削除され、-zNULL 終了レコードを処理できるように再度削除されます。

重要:このスクリプトはGNUツールを使用していると想定しています。メディアライブラリを開くLinuxと主張してDebianを実行しているので、あなたに役立ちます。しかし、私はそのシステムを使ったことがないので、確信できません。

おすすめ記事