我在Windows中有一个充满文件的目录(已导出的Dynamics NAV对象的文本导出)。每个文件包含多个对象。我需要根据以OBJECT开头的行将每个文件拆分为单独的文件,并相应地命名每个文件。
这样做的目的是将我们的Dynamics NAV系统变成git。
我写了一个漂亮的perl程序来做这个在linux上运行得很好的程序。但它依赖于Windows中的while(<>)循环(Server 2012,如果这很重要)。
所以,我需要弄清楚如何在我编写的PowerShell脚本中执行此操作,生成所有文件,或者修复我从PowerShell调用的perl脚本。 Windows perl处理文件句柄的方式与linux不同吗?
这是我的代码:
#!/usr/bin/perl
use strict;
use warnings;
use File::Path qw(make_path remove_tree);
use POSIX qw(strftime);
my $username = getlogin || getpwuid($<);
my $datestamp = strftime("%Y%m%d-%H%M%S", localtime);
my $work_dir = "/temp/nav_export";
my $objects_dir = "$work_dir/$username/objects";
my $export_dir = "$work_dir/$username/$datestamp";
print "Objects being exported to $export_dir\n";
make_path("$export_dir/Page", "$export_dir/Codeunit", "$export_dir/MenuSuite", "$export_dir/Query", "$export_dir/Report", "$export_dir/Table", "$export_dir/XMLport");
chdir $objects_dir or die "Could not change to $objects_dir: $!";
# delete empty files
foreach(glob('*.*')) {
unlink if -f and !-s _;
}
my @files = <*>;
my $count = @files;
print "Processing $count files\n";
open (my $fh, ">-") or die "Could not open standard out: $!";
# OBJECT Codeunit 1 ApplicationManagement
while(<>)
{
if (m/^OBJECT ([A-Za-z]+) ([0-9]+) (.*)/o)
{
my $objectType = $1;
my $objectID = $2;
my $objectName = my $firstLine = $3;
$objectName =~ s/[\. \/\(\)\\]/_/g; # translate spaces, (, ), ., \ and / to underscores
$objectName =~ tr/\cM//d; # get rid of Ctrl-M
my $filename = $export_dir . "/" . $objectType . "/" . $objectType . "~" . $objectID . "~" . $objectName;
close $fh and open($fh, '>', $filename) or die "Could not open file '$filename' $!";
print $fh "OBJECT $objectType $objectID $firstLine\n";
next;
}
print $fh $_;
}
过去几天我学到了很多PowerShell。有些事情确实非常好。还有一些(比如调用带有变量的可执行文件和有空格的命令行选项),这些都令人抓狂。要调用curl,这就是我使用的:
$curl = "C:\Program Files (x86)\cURL\bin\curl"
$arg10 = '-s'
$arg1 = '-X'
$arg11 = 'post'
$arg2 = '-H'
$arg22 = '"Accept-Encoding: gzip,deflate"'
$arg3 = '-H'
$arg33 = '"Content-Type: text/xml;charset=UTF-8"'
$arg4 = '-H'
$arg44 = '"SOAPAction:urn:microsoft-dynamics-schemas/page/permissionrange:ReadMultiple"'
$arg5 = '--ntlm'
$arg6 = '-u'
$arg66 = 'username:password'
$arg7 = '-d'
$arg77 = '"@soap_envelope.txt"'
$arg8 = "http://$servicetier.corp.company.net:7047/$database/WS/DBDOC/Page/PermissionRange"
$arg9 = "-o"
$arg99 = "c:\temp\nav_export\$env:username\raw_list.xml"
&"$curl" $arg10 $arg1 $arg11 $arg2 $arg22 $arg3 $arg33 $arg4 $arg44 $arg5 $arg6 $arg66 $arg7 $arg77 $arg8 $arg9 $arg99
我意识到这部分有点切线。但是我一直在努力想要解决这个问题,而不必在stackoverflow上打扰你们好心人!
我对使其在PowerShell中工作或修复Perl代码感到矛盾。我只需要让它工作。但我希望它与linux和Windows之间的文件句柄处理有一些区别。
答案 0 :(得分:1)
很难相信你展示的Perl代码在Linux上做了什么。看起来您的while
循环应该读取@files
数组中的所有文件,但为了做到这一点,您必须将名称复制到@ARGV
。
另请注意,@files
将包含目录和文件。
我建议您将以my @files = <*>
开头的行更改为此。它没有理由不适用于Windows和Linux。
our @ARGV = grep -f, glob '*';
my $count = @ARGV;
print "Processing $count files\n";
my $fh;
while (<>) {
s/\s+\z//; # Remove trailing whitespace (including CR and LF)
my @fields = split ' ', $_, 4;
if ( @fields == 4 and $fields[0] eq 'OBJECT' ) {
my ($object_type, $object_id, $object_name) = @fields[1,2,3];
$object_name =~ tr{ ().\\/}{_}; # translate spaces, (, ), ., \ and / to underscores
my $filename = "$export_dir/$object_type/$object_type~$object_id~$object_name";
open $fh, '>', $filename or die "Could not open file '$filename': $!";
}
print $fh "$_\n" if $fh;
if (eof) {
close $fh;
$fh = undef;
}
}