Ls

ls -A 的錯誤輸出導致錯誤輸出,為什麼?

  • April 26, 2021

我有一個使用 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

檢查目錄是否為空可以通過其他方式在外殼本身內完成,但處理所有極端情況可能很麻煩。參見例如 攜帶式檢查空目錄

引用自:https://unix.stackexchange.com/questions/646416