【问题标题】:How can I run a shell script from inside a Perl script run by cron?如何从 cron 运行的 Perl 脚本中运行 shell 脚本?
【发布时间】:2023-07-27 17:23:01
【问题描述】:

是否可以在 cron 中运行带有 shell sript 的 Perl 脚本(vas.pl)(date.sh 和 backlog.sh),反之亦然? 谢谢。

 0 19 * * * /opt/perl/bin/perl /reports/daily/scripts/vas_rpt/vasCIO.pl 2> /reports/daily/scripts/vas_rpt/vasCIO.err

遇到错误:

 date.sh: not found
 backlog.sh: not found

Perl 脚本:

#!/opt/perl/bin/perl

system("sh date.sh");
open(FH,"/reports/daily/scripts/vas_rpt/date.txt");
@date = <FH>;

close FH;

open(FH,"/reports/daily/scripts/vas_rpt/$cat1.txt");
@array = <FH>;

system("sh backlog.sh $date[0] $array[0]");

close FH;

【问题讨论】:

    标签: perl shell scripting cron


    【解决方案1】:

    您的脚本中有很多需要注意的地方,我在Mastering Perl 的“安全编程技术”一章中谈到了其中的大部分内容。您也可以在perlsec/

    中找到其中的一些内容

    由于您正在获取外部数据并将它们传递给其他外部程序,因此您应该使用污点检查来确保数据符合您的预期。如果有人能够在这些文件中偷偷添加一些额外的东西怎么办?

    当您想将数据传递给外部程序时,请在列表形式中使用 system,这样 shell 就没有机会解释可能的元字符。

    不要依赖PATH 来查找您希望运行的程序,而是明确指定它们的完整路径,以确保您至少正在运行您认为的文件(而不是有人偷偷溜进一个早在PATH)。如果您真的很偏执(就像污点检查一样),您还可以检查这些文件和目录是否具有合适的权限(例如,不可全局写入)。

    作为补充说明,如果您只需要文件句柄中的一行,则可以在标量上下文中使用行输入运算符:

     my $date = <$fh>;
    

    您可能也想chomp 数据以摆脱可能的结尾换行符。即使您认为不应该存在终止换行符,因为另一个程序创建了该文件,使用文本编辑器查看该文件的人也可能会添加它。

    祝你好运,:)

    【讨论】:

      【解决方案2】:

      cron 在与当前工作目录不同的工作目录中运行您的 perl 脚本。使用脚本文件的完整路径:

      # I'm assuming your shell script reside in the same
      # dir as your perl script:
      
      system("sh /reports/daily/scripts/date.sh");
      

      或者,如果您像我一样对硬编码路径过敏,您可以使用 CPAN 的 FindBin 包:

      use FindBin qw($Bin);
      system("sh $Bin/date.sh");
      

      如果您的 shell 脚本也需要以正确的路径启动,那么最好先更改您的工作目录:

      use FindBin qw($Bin);
      chdir $Bin;
      system("sh date.sh");
      

      【讨论】:

      • @slebetman:正在运行的 shell 脚本的“home/start”目录是什么?我想我有点偏执,但我会确保那里有一个“cd /reports/daily/scripts”或者脚本写入绝对路径。 (以及我的 +1 解决方案和替代方案)
      • @lexu:你是对的。为了安全起见,应该在启动 shell 脚本之前更改当前工作目录。但是由于 OP 提到简单地添加完整路径解决了他的问题,那么在他的情况下他不需要它。
      【解决方案3】:

      只要你小心,你就可以为所欲为。

      对于cron 工作,首先要记住的是您几乎没有设置任何环境。

      很有可能,当前目录是/$HOME。并且 $PATH 的值很小 - 例如,您的配置文件尚未运行。

      所以,您的脚本没有找到“date.sh”,因为它不在正确的目录中。

      要从 shell 脚本中获取数据到您的程序中,您需要将其通过管道传输到那里 - 或安排“date.sh”将数据成功转储到文件中。当然,Perl 具有内置的日期和时间处理功能,因此您无需使用 shell。

      您也没有使用use warnings;use strict; 运行,这也会对您有所帮助。例如,$cat1 不是已定义的变量。

      就个人而言,我从cron 运行一个简单的shell 脚本,让它处理所有的复杂性;我不在 crontab 文件中使用 I/O 重定向。这部分是在古代系统上工作的遗产 - 但它也导致cron 作业的可移植和可靠运行。

      【讨论】:

      • 感谢您的建议!它有很大帮助:-)
      【解决方案4】:

      这是可能的。请记住,在 cron 下运行时您的工作目录可能不是您认为的那样 - 它是您的 HOME 环境变量中的值,或者在 /etc/passwd 文件中指定的值。考虑完全限定 .shes 的路径。

      【讨论】: