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

Need to split multiple files in a directory based on string, rename properly using powershell or fix my perl script

我在 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 = ;
        my $objectID = ;
        my $objectName = my $firstLine = ;
        $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

我意识到那部分有点离题。但是我一直在非常努力地尝试解决这个问题,而不必在 Whosebug 上打扰你们这些好人!

此时我对让它在 PowerShell 中工作或修复 Perl 代码持矛盾态度。我只需要让它工作。但我希望 linux 和 Windows.

之间的文件句柄处理略有不同

很难相信您展示的 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;
    }
}