该脚本从命令行运行,但 crontab 失败

Posted

技术标签:

【中文标题】该脚本从命令行运行,但 crontab 失败【英文标题】:The script runs from command line but crontab fails 【发布时间】:2011-10-03 20:36:47 【问题描述】:

我仍在学习 Bash,但我的脚本有问题。我想使用此脚本过滤一些呼叫,该脚本正在分析呼叫日志,每 2 分钟作为 cronjob。问题是我可以手动运行它,但是从 cron 自动运行时会失败。我不知道为什么。它喊了一些关于权限的东西,所以我对脚本进行了修补,所以如果它看起来很脏,我很抱歉。

#!/bin/bash

YESTERDAY=$((`date +'%s'`-86400))
AYER=`date -d "1970-01-01 $YESTERDAY sec" +"%Y%m%d"`
FECHA=`date +"%Y%m%d"`

FILENAME="$FECHA.log"
FILE_LINE="$FECHA.last"
FILE="/apps/sittel/rawdata/mitel.$FECHA"

# Limpiar carpeta tmp

if [ -e "tmp/$AYER.lnum" ]; then
    rm tmp/$AYER.*
fi

# Si existe el archivo con el numero de laultima linea se procesa

if [ -e "tmp/$FECHA.lnum" ]; then

    # Se lee el numero de la linea y se extrae un archivo con las lineas apartir
    # de la ultima busqueda que se hizo, posteriormente se les hace un grep

    while read line
    do
            tail -n +$line $FILE > "tmp/$FECHA.hal"
    done < "tmp/$FECHA.lnum"
    cd tmp

    grep -n " 00[0|2-9][0-9]\4,\" "tmp/$FECHA.hal" > "tmp/$FECHA.new"

    grep -n " 900[0|2-9][0-9]\4,\" "tmp/$FECHA.hal" >> "tmp/$FECHA.new"

    cd ..
    echo `pwd`
    cat tmp/$FECHA.new >> logs/$FILENAME

else
    # Este caso es la primera vez que se ejecuta, verifica si el log ya existe
    # de ser asi, lo elimina para evitar duplicados

    if [ -e "logs/$FILENAME" ]; then
            rm "logs/$FILENAME"
    fi

    # Se realiza un grep en el archivo indicado y se marca el archivo de salida
    # se busca todos los numeros k empiecen con 00 seguidos de 0 a 9 execpto el 1

    cd tmp

    grep -n " 00[0|2-9][0-9]\4,\" $FILE>"$FECHA.new"

    grep -n " 900[0|2-9][0-9]\4,\" $FILE>>"$FECHA.new"

    cat $FECHA.new >> $FILENAME

    mv $FILENAME ../logs

    cd ..
fi

    cp "tmp/$FECHA.new" "tmp/message.txt"

    echo "Mensaje" | mail -s "$SUBJECT" "$EMAIL" < "tmp/message.txt"

fi

if [ -e "tmp/$FECHA.new" ]; then
    rm "tmp/$FECHA.new"
fi

tail -n1 "logs/$FILENAME" > "tmp/$FILE_LINE"   

IFS=$':'
while read line
do
    DATOS=($line)
    LINE_NUMBER=$DATOS[0]   
    echo $LINE_NUMBER > "tmp/$FECHA.lnum"
done < "tmp/$FILE_LINE"
unset IFS

这是系统打印的内容:

/apps/sittel/Alarma/callAlarm: line 56: cd: tmp: No such file or directory
mv: cannot move `20110712.log' to `../logs': Permission denied
/apps/sittel/Alarma/callAlarm: line 69: tmp/20110712.last: No such file or directory
/apps/sittel/Alarma/callAlarm: line 77: tmp/20110712.last: No such file or directory

【问题讨论】:

关于 cron 与交互式 shell 会话的问题对于 superuser.com 来说更为热门。我已投票决定将这篇文章迁移到那里,如果有足够多的人同意我的观点,它将自动迁移。 【参考方案1】:

您的脚本假定它是从特定目录运行的(请注意,几乎每个路径都是相对路径,而不是绝对路径)。 cron 恰好是从另一个目录运行它。

修复

如果脚本在您从其所在目录运行时有效,请将以下内容添加到脚本顶部:

mydir=$(dirname "$0") && cd "$mydir" || exit 1

说明

$0 是正在执行的 shell 脚本的(可能是相对的)文件名。给定文件名,dirname 命令返回包含文件名的目录。

因此,如果dirnamecd 失败,则该行会将目录更改为包含脚本的目录或以错误代码退出。

【讨论】:

【参考方案2】:

您似乎假设某个起始目录,并在那里创建一个tmp 目录。但是,当您将它作为 cron 作业运行时,它会从不同的位置开始。所以 bash 启动脚本中的 CD 命令可能会搞砸你。当您 cdrm 或其他任何内容时,您可以使用完整路径名轻松测试。

例如,

if [ -e "tmp/$AYER.lnum" ]; then
    rm /home/username/tmp/$AYER.*
fi

# Si existe el archivo con el numero de laultima linea se procesa

if [ -e "/home/username/tmp/$FECHA.lnum" ]; then

    # Se lee el numero de la linea y se extrae un archivo con las lineas apartir
    # de la ultima busqueda que se hizo, posteriormente se les hace un grep

    while read line
    do
            tail -n +$line $FILE > "/home/username/tmp/$FECHA.hal"
    done < "/home/username/tmp/$FECHA.lnum"
    cd /home/username/tmp

    grep -n " 00[0|2-9][0-9]\4,\" "/home/username/tmp/$FECHA.hal" > "/home/username/tmp/$FECHA.new"

等等。

【讨论】:

【参考方案3】:

看起来您可能需要在脚本开始时将cd 放入正确的目录。

在开头放一个pwd,然后是exit,然后观察cron 输出,看看你是从哪里执行的。在 cron 下运行时,您也有可能拥有较短的 PATH,但它仍然应该可以访问 tailgrep

【讨论】:

以上是关于该脚本从命令行运行,但 crontab 失败的主要内容,如果未能解决你的问题,请参考以下文章

当它从命令行 bash 工作时,无法从 crontab 运行 bash 脚本

解决命令行执行shell脚本成功,但crontab执行失败

crontab 是不是接受命令行参数? [关闭]

将变量传递给从命令行运行的 PHP 脚本

脚本从 R 运行,但不是通过命令行

从命令行运行但不能通过 cron 运行时脚本运行良好