如果没有用户输入,Shell 脚本不会将 stdout 的最后一行绘制到屏幕上

如果没有用户输入,Shell 脚本不会将 stdout 的最后一行绘制到屏幕上

我有一个 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;我已经对其进行了大量编辑,但lzmagzip代码来自那里。)

答案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”,因为附加到字符设备和写入字符设备之间没有区别,因为字符设备不可查找。

相关内容