ls -A 的錯誤輸出導致錯誤輸出,為什麼?
我有一個使用 cron 定期執行的腳本。當這些腳本失敗時,我想通過電子郵件收到通知。我不希望每次執行並產生任何輸出時都收到通知。
因此,我使用腳本Cronic在 cron 中執行我的作業,這應該意味著只發送錯誤輸出,而不僅僅是任何輸出。
但是,在一個腳本中,我有一個這樣的命令:
if [ "$(ls -A ${local_backup_location}/nextcloud-data/)" ]; then # save space by removing diffs older than 6 months rdiff-backup --remove-older-than 6M --force ${local_backup_location}/nextcloud-data/ || echo "[$(date "+%Y-%m-%d %T")] No existing nextcloud data backup" fi
ls -A ${local_backup_location}/nextcloud-data/
旨在測試目錄是否為空。我的問題是這個命令似乎導致輸出被辨識為錯誤輸出cronic。Cronic 將錯誤定義為任何非跟踪錯誤輸出或非零結果程式碼。例如:Cronic detected failure or error output for the command: /usr/local/sbin/run_backup RESULT CODE: 0 ERROR OUTPUT: appdata_ocgcv9nemegb files_external flow.log flow.log.1 __groupfolders .htaccess index.html nextcloudadmin nextcloud-db.bak nextcloud.log nextcloud.log.1 .ocdata rdiff-backup-data Test_User updater.log updater-ocgcv9nemegb ] custom gitea-db.sql log ] % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 100 365 0 0 100 365 0 302 0:00:01 0:00:01 --:--:-- 303 100 365 0 0 100 365 0 165 0:00:02 0:00:02 --:--:-- 165 100 365 0 0 100 365 0 113 0:00:03 0:00:03 --:--:-- 113 100 365 0 0 100 365 0 86 0:00:04 0:00:04 --:--:-- 86 100 365 0 0 100 365 0 70 0:00:05 0:00:05 --:--:-- 70 100 365 0 0 100 365 0 58 0:00:06 0:00:06 --:--:-- 0 100 365 0 0 100 365 0 50 0:00:07 0:00:07 --:--:-- 0 100 365 0 0 100 365 0 44 0:00:08 0:00:08 --:--:-- 0 100 365 0 0 100 365 0 39 0:00:09 0:00:09 --:--:-- 0 100 365 0 0 100 365 0 37 0:00:09 0:00:09 --:--:-- 0 100 10.4M 0 10.4M 100 365 1016k 34 0:00:10 0:00:10 --:--:-- 2493k 100 11.6M 0 11.6M 100 365 1128k 34 0: 00:10 0:00:10 --:--:-- 3547k STANDARD OUTPUT: Maintenance mode enabled Deleting increment at time: <snip>
那麼為什麼
ls -A ${local_backup_location}/nextcloud-data/
在這種情況下該命令會產生錯誤輸出,我該如何防止呢?另一種測試目錄是否為空的可靠方法是可以接受的,但我也想解釋一下為什麼該命令似乎會產生錯誤輸出。編輯:添加 Cronic 標準輸出
set -ex
一些評論者要求提供非常長的實際整個腳本,但 Cronic 報告了腳本的實際標準輸出,我
set -ex
在腳本頂部使用。錯誤輸出在呼叫之後立即發生,ls -A /mnt/reos-storage-2/backups/nextcloud-data/
這就是為什麼我認為錯誤輸出是該命令的結果。+ rdiff-backup --ssh-no-compression /var/www/nextcloud /mnt/reos-storage-2/backups/nextcloud/ + ls -A /mnt/reos-storage-2/backups/nextcloud-data/ + [ 67cf481e-62a3-1039-8bf2-05805d214bca <removed> appdata_ocgcv9nemegb <removed> <removed> <removed> <removed> files_external flow.log flow.log.1 __groupfolders .htaccess index.html <removed> <removed> nextcloudadmin nextcloud-db.bak nextcloud.log nextcloud.log.1 .ocdata <removed> <removed> rdiff-backup-data <removed> Test_User <removed> updater.log updater-ocgcv9nemegb ] + rdiff-backup --remove-older-than 6M --force /mnt/reos-storage-2/backups/nextcloud-data/ + date +%Y-%m-%d %T + echo [2021-04-21 03:23:38] Starting nextcloud data backup
+ [ 67cf481e-62a3-1039-8bf2-05805d214bca <刪除> *[...]* 更新程序日誌 更新程序-ocgcv9nemegb ]
這是一個單一的命令。
set -x
它在/輸出中被拆分為多行xtrace
,因為來自的輸出ls
包含換行符。(Bash 會列印一些引號,而 Dash 不會。)預設情況下,
xtrace
輸出到 stderr,與正常錯誤輸出相同,Cronic 嘗試通過查看行+
開頭的標記來將它們分開xtrace
。這在這裡失敗了,它認為那裡的文件名是正常錯誤輸出的一部分。cronic 所做的基本上是這樣的:
PATTERN="^${PS4:0:1}\\+${PS4:1}" if grep -aq "$PATTERN" $TRACE then ! grep -av "$PATTERN" $TRACE > $ERR
禁用
xtrace
將是解決此問題的一種方法,但這樣做會很遺憾,因為 cronic 非常支持它。相反,最好使用其他方法來檢查目錄是否為空。
與 保持一致
ls -A
,您可以將輸出通過管道傳輸wc
到以計算那裡的字元:if [ "$(ls -A "${local_backup_location}/nextcloud-data/" | wc -c)" -gt 0 ]; then echo "directory not empty" fi
或
grep
:if ls -A "${local_backup_location}/nextcloud-data/" | grep -q .; then echo "directory not empty"; fi
檢查目錄是否為空可以通過其他方式在外殼本身內完成,但處理所有極端情況可能很麻煩。參見例如 攜帶式檢查空目錄