昨天,我问了一个类似的问题,即在环境变量中转义双引号,尽管它不能解决我的问题(可能是因为我的解释不够好),所以我想指定更多。
我正在尝试运行脚本(我知道该脚本是用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"
另一条注释,在外壳程序上使用\"
失败(尝试过)。
关于如何找到错误原因以及如何解决错误的任何建议?
答案 0 :(得分:2)
从$args
获得的%ENV
是一个字符串。
问题在于在将参数传递给程序之前,该字符串在被操纵之前会发生什么变化,该程序需要接收字符串-arg
和date time
如果您以示例的方式绕过Shell执行程序,则整个-arg "date time"
将作为其第一个参数传递给它。显然,这是错误的,因为程序需要-arg
,然后是其值的另一个字符串(date time
)
如果程序是通过shell执行的,那么当命令行中有shell元字符(在您的示例中未出现)时会发生什么,则shell会将字符串分解为单词,除了带引号的部分;这是在命令行中的工作方式。可以通过
强制执行system('/bin/tcsh', '-c', $cmd);
这是最简单的解决方法,但是老实说,我不建议仅将外壳程序用于参数解析。另外,您现在还处于分层报价和转义的游戏中,可能会涉及到很多麻烦的事情。例如,如果事情不正确,shell可能最终会将命令分解为单词-arg
,"date
,time"
如何设置环境变量有效
> setenv SOME_ENV '-arg "date time"'
> perl -wE'say $ENV{SOME_ENV}' #--> -arg "date time" (so it works)
我认为在[t]csh
中一直如此工作。
然后,在Perl脚本中:将此字符串解析为-arg
和date 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::Simple,Capture::Tiny,IPC::Run3和IPC::Run。
我必须注意,这是一个尴尬的环境变量;有什么方法可以使事情变得残酷吗?
†Â还要使未引用的参数(-arg date
)起作用,请将引号设为可选
my @args = $ENV{SOME_ENV} =~ /(\S+)\s+"?([^"]+)/;
为简单起见,我在此处省略了结束语(不必要的)