如何通过 crontab 运行脚本并为脚本输入值?

如何通过 crontab 运行脚本并为脚本输入值?

我正在尝试在 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..."
    

相关内容