需要根据字符串拆分目录中的多个文件,使用powershell正确重命名或修复我的perl脚本

时间:2015-01-18 02:02:25

标签: windows perl powershell file-io powershell-v3.0

我在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之间的文件句柄处理有一些区别。

1 个答案:

答案 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;
    }
}