脚本仅使用双引号的第一部分

时间:2018-07-24 06:25:08

标签: shell perl environment-variables double-quotes

昨天,我问了一个类似的问题,即在环境变量中转义双引号,尽管它不能解决我的问题(可能是因为我的解释不够好),所以我想指定更多。

我正在尝试运行脚本(我知道该脚本是用Perl编写的),尽管由于权限问题我不得不将其用作黑匣子(因此我不知道脚本的工作原理)。让我们将此脚本称为script_A

我正在尝试在Shell中运行基本命令:script_A -arg "date time"。 如果我从命令行运行,则可以正常工作,但是,如果我尝试从bash脚本或perl脚本中使用它(例如,使用system运算符),它将仅使用字符串的第一部分,被作为论点发送。换句话说,它将失败并显示以下错误:'"date' is not valid.

更多指定示例:

  • 如果我从命令行运行(工作正常):

    > script_A -arg "date time"
    
  • 例如,如果我从Perl脚本运行(失败):

    my $args = $ENV{SOME_ENV}; # Assume that SOME_ENV has '-arg "date time"'
    my $cmd = "script_A $args";
    system($cmd");
    

我认为问题出在环境变量,但是在定义env变量时不能使用单引号。例如,我不能使用以下方法:

setenv SOME_ENV '-arg "date time"'

因为它失败,并出现以下错误:'"date' is not valid."

此外,我尝试使用以下方法:

setenv SOME_ENV "-arg '"'date time'"'"

尽管现在env变量将包含:

echo $SOME_ENV
> -arg 'date time' # should be -arg "date time"

另一条注释,在外壳程序上使用\"失败(尝试过)。

关于如何找到错误原因以及如何解决错误的任何建议?

1 个答案:

答案 0 :(得分:2)

$args获得的%ENV是一个字符串。

问题在于在将参数传递给程序之前,该字符串在被操纵之前会发生什么变化,该程序需要接收字符串-argdate time

  • 如果您以示例的方式绕过Shell执行程序,则整个-arg "date time"将作为其第一个参数传递给它。显然,这是错误的,因为程序需要-arg,然后是其值的另一个字符串(date time

  • 如果程序是通过shell执行的,那么当命令行中有shell元字符(在您的示例中未出现)时会发生什么,则shell会将字符串分解为单词,除了带引号的部分;这是在命令行中的工作方式。可以通过

    强制执行
    system('/bin/tcsh', '-c', $cmd);
    

    这是最简单的解决方法,但是老实说,我不建议仅将外壳程序用于参数解析。另外,您现在还处于分层报价和转义的游戏中,可能会涉及到很多麻烦的事情。例如,如果事情不正确,shell可能最终会将命令分解为单词-arg"datetime"

如何设置环境变量有效

> setenv SOME_ENV '-arg "date time"'   

> perl -wE'say $ENV{SOME_ENV}'  #--> -arg "date time"  (so it works)

我认为在[t]csh中一直如此工作。

然后,在Perl脚本中:将此字符串解析为-argdate time字符串,并以跳过shell的方式执行程序(如果命令未使用shell) )

my @args = $ENV{SOME_ENV} =~ /(\S+)\s+"([^"]+)"/;  #"

my @cmd = ('script_A', @args);

system(@cmd) == 0  or die "Error with system(@cmd): $?";

这假设SOME_ENV的第一个单词始终是选项的名称(-arg),而其余所有单词始终都是选项的引号引起来的值。正则表达式提取第一个单词,作为连续的非空格字符,然后将所有内容都用引号引起来。这些是程序的参数。

system LIST的形式在不使用shell的情况下执行了列表的第一个元素的程序,其余元素作为参数传递给它。请参阅system,以获取更多信息,以及有关通过研究$? variable来调查故障的基础知识。

原则上建议在没有外壳的情况下运行外部命令。但是,如果您的命令需要外壳程序,请确保对字符串进行转义以保留引号。

请注意,有些模块使使用外部命令更加容易。从简单到复杂的一些:IPC::System::SimpleCapture::TinyIPC::Run3IPC::Run

我必须注意,这是一个尴尬的环境变量;有什么方法可以使事情变得残酷吗?


Â还要使未引用的参数(-arg date)起作用,请将引号设为可选

my @args = $ENV{SOME_ENV} =~ /(\S+)\s+"?([^"]+)/;

为简单起见,我在此处省略了结束语(不必要的)