我正在尝试在 Linux 上使用 crontab 运行一个脚本,如下所示,我创建了一个增量备份脚本。
当我在命令行中执行时,/usr/bin/diego-backup.sh complete
脚本会创建系统的完整备份,if not creates it incremental
问题出现在我将其配置为通过 crontab 运行时,0 0 * * * (/usr/bin/diego-backup.sh complete && /usr/bin/diego-virt-starten.sh)
在这种情况下,备份脚本会创建一个文件,但它不是完整备份。
谁能告诉我我做错了什么?
脚本 1:关闭所有虚拟机
virsh shutdown Odoo
virsh shutdown OpenZ
virsh shutdown mssqlserver
virsh shutdown Zentyal_HOME
脚本 2:创建备份
#cat > /usr/local/sbin/backup.sh << EOF
#!/bin/sh
BACKUPDIR=/media/backup
LASTMONTHDIR=lastmonth
TSNAME=timestamp.snar
BACKUPNAME=backup
DIRS="/"
if [ $1 == "complete" ]; then
#Komplettes Backup
MYDATE=complete
#Alte Timestamps löschen
rm -f "$BACKUPDIR/$TSNAME"
#Alte Backups löschen
rm -rf "$BACKUPDIR/$LASTMONTHDIR.$BACKUPNAME.d"
#Neue alte Backups in Ordner verschieben
mkdir "$BACKUPDIR/$LASTMONTHDIR.$BACKUPNAME.d"
mv -f "$BACKUPDIR/$BACKUPNAME.*".tgz
"$BACKUPDIR/$LASTMONTHDIR.$BACKUPNAME.d"
else
#Inkrementelles Backup
MYDATE=$(date +%y%m%d)
fi
#Abzug erstellen
tar czf "$BACKUPDIR"/"$BACKUPNAME".$MYDATE.tgz --exclude=/proc --exclude=/lost+found --exclude=/media --exclude=/mnt$
#EOF chmod +x /usr/local/sbin/backup.sh
脚本 3:启动虚拟机
#!/bin/sh
sudo echo "Starte die Virtual Maschinen an..."
xmlfiles=( $(find /etc/libvirt/qemu/autostart/ -name '*.xml') )
for f in "${xmlfiles[@]}" ; do
domain=$(xml2 < $f | awk -F= '$1 == "/domain/name" {print $2}')
# only start domain if it's not already running
if ! virsh list | grep " ${domain} .*running" ; then
virsh start "$domain"
#else
# optionally reboot domain otherwise
#virsh reboot "$domain"
fi
done
Crontab 如下:
41 12 * * * /usr/bin/diego-virt-stoppen.sh >> /home/sysadm/`date +\%Y\%m\%d\%H\%M\%S`-virt-stop.log 2>&1
48 15 * * * (/usr/bin/diego-backup.sh complete && /usr/bin/diego-virt-starten.sh) >> /home/sysadm/`date +\%Y\%m\%d\%$`
谢谢!
答案1
错误信息:
/usr/bin/diego-backup.sh: 11: [: complete: unexpected operator
表明此比较存在问题:
if [ $1 == "complete" ]; then
(注意:这不是所示脚本的第 11 行;是否遗漏了一些空行?)
问题是,对于该命令来说,这==
是一个非标准的比较运算符。的内置版本接受作为的同义词,但我猜你是在较新版本的 Debian 或 Ubuntu 上运行这个命令,其中[
bash
[
==
=
/bin/sh 是dash
,一个更基本的 shell。dash
的内置版本 [
不支持==
,并给出报告的错误消息:
$ [ complete == complete ] && echo "Match succeeded" || echo "Match failed"
sh: 1: [: complete: unexpected operator
Match failed
您可以通过切换到标准=
比较来解决这个问题:
$ [ complete = complete ] && echo "Match succeeded" || echo "Match failed"
Match succeeded
或者将脚本的 shebang 行更改为#!/bin/bash
(或#!/usr/bin/env bash
),这样脚本将在 中运行,bash
而不是dash
。我实际上建议同时进行这两项更改,并更改所有脚本中的 shebang;bash
当标准形式同样有效时,使用非标准形式是没有意义的,但如果您不太熟悉标准与 bashisms,强制执行更安全,bash
这样您就不会再次遇到这样的问题。
(仔细想想,我不知道你的第三个脚本为什么可以工作。它使用数组,这是另一个bash
支持但dash
不支持的东西。)
顺便说一句,我还有一些其他建议:
无论使用哪种形式的比较,都应该对参数引用使用双引号,以避免在参数引用长度不完全为一个单词时出现麻烦(对字符串使用双引号
complete
不是必需的,但也不会造成任何损害):if [ "$1" = "complete" ]; then
你应该使用小写或混合大小写的变量名(参见第 4 段这里)。有很多全大写的变量名对 shell 和/或其他程序具有特殊含义,如果你错误地使用这些变量名,可能会导致奇怪的结果(例子)。
在这一行中:
mv -f "$BACKUPDIR/$BACKUPNAME.*".tgz "$BACKUPDIR/$LASTMONTHDIR.$BACKUPNAME.d"
...通配符需要外部引文以便扩展:
mv -f "$BACKUPDIR/$BACKUPNAME".*.tgz "$BACKUPDIR/$LASTMONTHDIR.$BACKUPNAME.d"
如果脚本(尤其是第二个脚本)有一些错误检查,我会感到更安全。例如,如果
$BACKUPNAME.d
由于某种原因创建新目录失败,脚本盲目继续并尝试将旧文件移动到非目录中是没有意义的。您可以使用set -e
(或添加-e
到 shebang)让它在任何命令失败时退出,但这可能会意想不到的结果就我个人而言,我更喜欢强迫自己思考脚本中的每个步骤、失败的后果,以及明确地编写脚本来处理它们:rm -f "$BACKUPDIR/$TSNAME" || { echo "$0: Error deleting backup timestamps; cancelling backup" >&2 echo "$0: A human will need to debug this before it can proceed" >&2 exit 1 }
最后,
sudo
这里没有做任何有用的事情:sudo echo "Starte die Virtual Maschinen an..."