1

我正在尝试使用 sed 删除第一行并删除后续行中的前导和尾随空格

如果我有类似的东西

第1行
     线2
  第 3 行

它应该打印

线2
第 3 行

所以我在 unix shell 上尝试了这个命令:

sed '1d;s/^ [ \t]*//;s/[ \t]*$//' file.txt

它按预期工作。

当我在我的 perl 脚本中尝试相同的操作时:

my @templates = `sed '1d;s/^ [ \t]*//;s/[ \t]*$//' $MY_FILE`;

它给了我这条消息“sed: -e expression #1, char 10: unterminated `s' command”并且不打印任何内容。有人能告诉我哪里出错了吗

4

6 回答 6

2

你为什么要从 Perl 调用 Sed 呢?用等效的 Perl 代码替换 sed 只是几个精心策划的击键。

my @templates;
if (open (M, '<', $MY_FILE)) {
    @templates = map { s/(?:^\s*|\s*$)//g; $_ } <M>;
    shift @templates;
    close M;
}  else { # die horribly? }
于 2013-09-18T19:52:32.650 回答
1

你的表达有错别字。您需要在 2 个替换语句之间使用分号。您应该改用以下内容:

my @templates = `sed '1d;s/^ [ \\t]*//;s/[ \\t]*\$//' $MY_FILE`;

转义$\按照另一个答案中的建议。我应该注意到,它也适用于我而无需转义\,因为它已被文字标签所取代。

于 2013-09-18T19:27:26.007 回答
1

正如其他人所提到的,我建议您仅在 Perl 中或仅在 Sed 中执行此操作,因为实际上没有理由将两者都用于此任务。在 Perl 中使用 Sed 意味着您必须担心以某种方式转义、引用和捕获输出(除非从管道读取)。显然,所有这些都使事情变得复杂,并且也使代码非常难看。

这是一个 Perl 单行代码,可以处理您的重新格式化:

perl -le 'my $line = <>; while (<>) { chomp; s/^\s*|\s*$//; print $_; }' file.txt

基本上,您只需将第一行存储在一个不会使用的变量中,然后处理其余的行。下面是一个小脚本版本,您可以将其添加到现有脚本中。

#!/usr/bin/env perl

use strict;
use warnings;

my $usage = "$0 infile";
my $infile = shift or die $usage;

open my $in, '<', $infile or die "Could not open file: $infile";

my $first = <$in>;

while (<$in>) {
    chomp;
    s/^\s*|\s*$//;

    # process your data here, or just print...
    print $_, "\n";
}
close $in;
于 2013-09-18T20:29:38.790 回答
1

反引号像双引号一样工作。Perl 会在其中插入变量,正如您已经知道的那样,因为您使用$MY_FILE. 您可能不知道的是,$/它实际上是一个变量,即输入记录分隔符(默认为换行符)。制表符之前的反斜杠也是如此。这里 Perl 将为\t您解释并用制表符替换它。您需要第二个反斜杠,以便 sed 看到\t而不是实际的制表符。不过,后者也可能有效。

于 2013-09-18T19:03:43.960 回答
1

考虑使用安全管道打开而不是反引号,以避免出现逃逸问题。例如:

my @templates = do {
    open my $fh, "|-", 'sed', '1d;s/^ [ \t]*//;s/[ \t]*$//', $MY_FILE
        or die $!;
    local $/;
    <$fh>;
};
于 2013-09-18T19:45:04.040 回答
0

这也可以与awk

awk 'NR>1 {$1=$1;print}' file
line2
line3
于 2013-09-19T08:41:30.387 回答