我有一个小的perl脚本,它从excel文件中收集文件路径,并通过命令行传递给perltex,然后perltex根据所选的文件和路径编译pdf。
我的问题是,当我引入更复杂的文件路径(这是基于最终用户池的网络设置所必需的)时,perltex无法找到文件路径,无法在空间中剪切它们。
MWE是以下
#!/usr/bin/perl
use strict;
use warnings;
use 5.14.2;
use Text::Template;
use Spreadsheet::Read;
use Spreadsheet::ParseXLSX;
use utf8;
use charnames qw( :full :short );
use autodie;
my $row = 5;
my $col = 15;
my $File = "C:/Users/me/Desktop/Reporting-Static/Input-test1.xlsm";
my $parser = Spreadsheet::ParseXLSX->new();
my $workbook = $parser->parse($File);
my $worksheet = $workbook->worksheet("Input");
my $cell = $worksheet->get_cell($row, $col);
my $Filename = $cell->Value();
my $texfile = "C:/Users/me/Desktop/Reporting-Static/file.tex";
# can't find this file if there are spaces in the address
system("perltex", "--latex=pdflatex", "--nosafe", "--jobname=$Filename", "$texfile");
if ( $? == -1 )
{
print "command failed: $!\n";
}
else
{
printf "command exited with value %d", $? >> 8;
}
exit;
然而,我将文件夹名称更改为带有空格的那一刻,例如。 "报告静态"它无法找到tex文件。
我已经在堆栈交换和其他网站上阅读了其他几篇关于此的帖子,但无论出于何种原因,建议的解决方案似乎对我不起作用。我试过了
my $texfile = "C:/Users/me/Desktop/Reporting Static/file.tex";
my $texfile = C:/Users/me/Desktop/"Reporting Static"/file.tex;
my $texfile = "\"C:/Users/me/Desktop/"Reporting Static"/file.tex\"";
my $texfile = "\"C:/Users/me/Desktop/Reporting Static/file.tex\"";
my $texfile = "C:/Users/me/Desktop/Reporting^ Static/file.tex";
my $texfile = "C:/Users/me/Desktop/Reporting\^ Static/file.tex";
除了以上的一些其他组合或变化之外,都没有成功。我也尝试用单引号替换双引号,以便perl不会内插内容。
我还尝试在命令提示符中手动输入上述所有内容,以检查perl是否将命令传递给命令行,但仍然没有运气。
我知道我可以使用' dir / X~1 c:\'命令查找避免空格的系统名称分配,但想法是文件名和位置将是动态的,并作为部门和网站的功能进行更改,所以我宁愿避免尝试编写一个脚本来查找此路径名,用它来替换所有使用空格或其他特殊字符的位置。
我最后的想法是,这个问题可能与perltex传递它的论据有关,但我无法找到任何文件(我可以遵循......)关于如何文件功能的这个特殊方面。
所以我的问题是,在我读到的关于如何正确地将这些路径传递给perltex的其他答案中,我是否缺少一些我没有注意到的内容,是否可能存在某种不兼容的问题。关于这一点,这是与perltex相关的更多概率而不是perl或cmd,还是有一些完全不同的东西,我不知道这是阻止它工作???
编辑: 从cmd提示符perltex返回"无法找到路径X,请输入另一个文件位置"。到目前为止,我还没有通过输入C:/ Users / me / Desktop /"报告静态" /file.tex'来测试重新输入路径。 (开头没有引号)随后被接受并运行。但最初传递它这条路径不起作用,这表明一些内部perltex代码接受初始路径不同,以便在错误后重新分配相同的路径....不太清楚该怎么做。
编辑: 我提取的@latexcmdline的内容
$VAR1 = [
'pdflatex',
'--jobname=--',
'\\makeatletter\\def\\plmac@tag{AYNNNUVKQVJGZKKPGPTH}\\def\\plmac@tofile{Perl.topl}\\def\\plmac@fromfile{Perl.frpl}\\def\\plmac@toflag{Perl.tfpl}\\def\\plmac@fromflag{Perl.ffpl}\\def\\plmac@doneflag{Perl.dfpl}\\def\\plmac@pipe{Perl.pipe}\\makeatother\\input C:/Users/me/Desktop/PERLTEST/Perl',
'Modules/RevuedeProjetDB.tex'
];
这是通过插入
来完成的 use File::Slurp;
use Data::Dumper;
write_file 'C:\Users\me\Desktop\PERLTEST\mydump.log', Dumper( \@latexcmdline );
在exec命令之前。
答案 0 :(得分:1)
我最初建议您使用String::ShellQuote
,但该模块仅适用于Linux,因此当我意识到您的问题是关于Windows系统时,我删除了我的答案
似乎还有Win32::ShellQuote
对Windows做同样的事情,所以我正在更新我的建议
正如我之前所说,问题是perltex本身并不能正确处理包含空格的路径,即使它们被正确地作为@ARGV
的单个元素传递。我相信解决方案是通过路径包括封闭引号,虽然我从来没有能够正确测试,因为我没有LaTex安装
不幸的是,即使我通过qq{"$texfile"}
,引号在到达目标程序之前仍然被剥离,所以它们必须以某种方式受到保护
您需要该模块中的quote_system
函数,该函数将准备一个字符串列表,以便它们保留任何引号
使用quote_system(qq{"$texfile"})
参数可以在我的测试中生成正确的结果。这相当于传递qq{"\\"$texfile\\""}
但不那么丑陋
所以你的系统调用应该是这样的(对perltex.pl进行 no 修改)
我已将相同的原则应用于$Filename
,因为它也可能包含空格
use Win32::ShellQuote 'quote_system';
system(quote_system(
'perltex',
'--latex=pdflatex',
'--nosafe',
qq{--jobname="$Filename"},
qq{"$texfile"},
));
好吧,我有各种各样的解决方案
我怀疑这个问题是,虽然路径作为单个字符串传递给perltex.pl
,但后者在收到路径时没有正确处理路径
临时解决方法是破解perltex.pl
我的perltex.pl
版本的第82行(源代码中没有版本号)读取
$latexcmdline[$firstcmd] = "\\input $option";
如果您将其更改为
$latexcmdline[$firstcmd] = qq{\\input "$option"};
然后一切都应该好。但是,只有当perltex
的作者分发时,这才是一个可靠的解决方案。与此同时,我正在寻找来自主叫方的更好的解决方案
答案 1 :(得分:0)
解决此问题有两个步骤。
对于第1步,我发现这样的程序很有用。
#!/usr/bin/perl
use strict;
use warnings;
print "Received ", scalar @ARGV, " arguments:\n";
for (1 .. @ARGV) {
print "$_: $ARGV[$_ - 1]\n";
}
它只是解释了它在命令行上收到的参数。您可以使用它代替“perltex”进行测试。
你会看到,如果你给它一个包含空格的参数,那么它被解释为被调用的程序作为多个参数。绕过的方法是引用包含空格的参数。我似乎记得Windows坚持使用双引号(出于我永远无法记住的原因)。
所以我认为你想要这个:
system('perltex', '--latex=pdflatex', '--nosafe', "--jobname=\"$Filename\"", "\"$texfile\"");
我已经双引两个文件名。当然,那些逃脱的双引号字符看起来真的很难看,Perl让我们qq(...)
让它看起来更漂亮。
system('perltex', '--latex=pdflatex', '--nosafe', qq(--jobname="$Filename"), qq("$texfile"));
如果那不太正确,那么我之前展示的程序将更容易找到解决方案。
更新:鲍罗丁的评论如下,对$texfile
没有任何影响是准确的。我们将列表传递给system()
的事实意味着shell根本不涉及。