【问题标题】:Get value of autosplit delimiter?获取自动拆分分隔符的值?
【发布时间】:2026-01-08 20:40:02
【问题描述】:

如果我使用perl -Fsomething 运行脚本,该 something 值是否保存在脚本可以找到的 Perl 环境中的任何位置?我想编写一个脚本,默认情况下重用输入分隔符(如果它是字符串而不是正则表达式)作为输出分隔符。

【问题讨论】:

    标签: perl command-line-arguments


    【解决方案1】:

    看着source,我不认为分隔符保存在任何地方。当你运行时

    perl -F, -an
    

    词法分析器实际生成代码

    LINE: while (<>) {our @F=split(q\0,\0);
    

    并解析它。此时,有关分隔符的任何信息都将丢失。


    您最好的选择是手动split

    perl -ne'BEGIN { $F="," } @F=split(/$F/); print join($F, @F)' foo.csv
    

    或将分隔符作为参数传递给您的脚本:

    F=,; perl -F$F -sane'print join($F, @F)' -- -F=$F foo.csv
    

    或将分隔符作为环境变量传递:

    export F=,; perl -F$F -ane'print join($ENV{F}, @F)' foo.csv
    

    【讨论】:

    • 这就是我害怕的。谢谢。
    • 顺便说一句,perl -F, -an 在技术上是多余的; -F 本身意味着-a-n(您可以通过手动指定-p 来覆盖)。包含它们可能更清楚,尽管当您编写单行而不是要保存的脚本时,清晰度通常不是优先事项。 :)
    【解决方案2】:

    正如@ThisSuitIsBlackNot 所说,分隔符似乎没有保存在任何地方。

    这就是perl.c 存储-F 参数的方式

    case 'F':
    PL_minus_a = TRUE;
    PL_minus_F = TRUE;
        PL_minus_n = TRUE;
    PL_splitstr = ++s;
    while (*s && !isSPACE(*s)) ++s;
    PL_splitstr = savepvn(PL_splitstr, s - PL_splitstr);
    return s;
    

    然后词法分析器生成代码

    LINE: while (<>) {our @F=split(q\0,\0);
    

    不过,这当然是经过编译的,如果您使用 B::Deparse 运行它,您可以看到存储的内容。

    $ perl -MO=Deparse -F/e/ -e ''
    LINE: while (defined($_ = <ARGV>)) {
        our(@F) = split(/e/, $_, 0);
    }
    -e syntax OK
    

    成为 perl 总是有办法的,无论多么丑陋。 (这是我一段时间以来写的最丑的代码):

    use B::Deparse;
    use Capture::Tiny qw/capture_stdout/;
    BEGIN {
        my $f_var;
    }
    
    unless ($f_var) {
        $stdout = capture_stdout {
            my $sub = B::Deparse::compile();
            &{$sub}; # Have to capture stdout, since I won't bother to setup compile to return the text, instead of printing
        };
    
        my (undef, $split_line, undef) = split(/\n/, $stdout, 3);
        ($f_var) = $split_line =~ /our\(\@F\) = split\((.*)\, \$\_\, 0\);/;
        print $f_var,"\n";  
    }
    

    输出:

    $ perl -Fe/\\\(\\[\\\<\\{\"e  testy.pl
    m#e/\(\[\<\{"e#
    

    您可以改为遍历字节码,因为在您到达模式之前,每次开始可能都是相同的。

    【讨论】:

    • 嗯,这令人印象深刻,但对我的应用程序来说有点矫枉过正。我只会做非自动拆分。