我有一个 shell 脚本,它很乐意执行所有备份过程并将进度写入 stderr 和 stdout,但有一个例外 - 最后一行不会写入我的终端(如果我手动调用脚本),直到我点击Enter。
现在这不是什么大问题,但它没有这样做真的让我很恼火,所以我想了解为什么它会这样做。
写入输出的内容(在我点击后Enter)如下:
[blackero@XXXXXXXXXXXXXXXX ~]$ fullbackup.sh
Tue Feb 28 17:57:41 GMT 2012
Tue Feb 28 17:57:41 GMT 2012
Starting SITE_NAME backup
maintenance_mode was set to 1. [success]
/home/blackero/bin/fullbackup.sh: line 36: hash: lzma: not found
maintenance_mode was set to 0. [success]
Backup for SITE_NAME created
[blackero@XXXXXXXXXXXXXXXX ~]$
脚本的相关部分如下(↪
表示我已将代码自动换行以方便阅读):
#!/bin/bash
date
date 2>&1
# [A bunch of content has been deleted from here]
# Compress with lzma if available, otherwise use gzip
if hash lzma; then
lzma -c ${backup_dest}/${dbname} >${backup_dest}/${dbname}.lzma
↪ && rm ${backup_dest}/${dbname}
else
gzip -c ${backup_dest}/${dbname} >${backup_dest}/${dbname}.gz
↪ && rm ${backup_dest}/${dbname}
fi
# Disable maintenance mode.
drush -r ${drupal_root} vset --always-set maintenance_mode 0
# Remove old backups >30 days
find ${backup_dest} -mtime +30 -exec rm {} \; >> /dev/null 2>&1
echo "Backup for ${sitename} created"
echo
echo 2>&1
因此,您可以看到if hash lzma; then
导致该hash: lzma: not found
行出现 stderr 的行(如果我可以抑制此消息,那就太好了,这样它就不会写入该警告,但我可以忍受它)。您可以看到正在将该行drush
写入标准maintenance_mode was set to 0.
输出。但Backup for SITE_NAME created
只有当我点击 时,这条线才会出现Enter。
这是因为上一个命令将 stdout 重定向到吗/dev/null
?我需要以某种方式撤消该重定向吗? (我认为流重定向只会自动影响单个命令。)
(警告:Fwiw,当这个脚本从 cron 运行时,stdout 和 stderr 重定向以附加到日志文件中,所有内容都会很高兴地写入日志文件,不需要终端输入。该脚本最初来自Drupal 的管理指南:fullsitebackup_drush
;我已经对其进行了大量编辑,但lzma
或gzip
代码来自那里。)
答案1
如果您的备份文件是只读的,则rm
运行的命令可能find
会提示您确认是否应删除备份文件。您看不到提示,因为您将其重定向到/dev/null。您Enter按下的键将被读取rm
(并采用rm
默认答案,即不删除文件)。
如果这个假设是正确的,您可以通过以下两种方法之一解决问题。一种是可移植的,但不安全,另一种是不可移植的,但更安全。尽管在这种情况下,安全差异可能很小(因为攻击者可能无法在 ${backup_dest} 中创建符号链接),但我会建议这两个选项:
安全的:
find "${backup_dest}" -depth -mtime +30 -delete
便携的:
find "${backup_dest}" -depth -mtime +30 \
'(' '(' -type d -exec rmdir {} \; -true ')' -o -exec rm -f {} \; ')'
最后,无需使用“>> /dev/null”而不是“"> /dev/null”,因为附加到字符设备和写入字符设备之间没有区别,因为字符设备不可查找。