【问题标题】:perl one-liner to split files every given wordperl one-liner 分割文件每个给定的单词
【发布时间】:2013-07-18 03:33:21
【问题描述】:

再次提出一些问题。我有一个格式的文件:

>seq1
123 234 56
167 332 22
23 456 098
>seq2
123 234 56
167 332 22
23 456 098

我想要一个文件保存每个>seq#,像这样:

文件 1:

>seq1
123 234 56
167 332 22
23 456 098

文件 2:

>seq2
123 234 56
167 332 22
23 456 098

我可以使用 perl 脚本,但想知道如何使用 perl 单行程序来完成,只是为了增加我的 perl 知识。

谢谢!!

【问题讨论】:

  • 你知道有很多生物模块,对吧? search.cpan.org
  • 是的,我知道,但我还是想试试单线就知道了。这些不是 fasta 文件,而是实际的数字表。
  • 除非有一个模块对此提供支持,否则您可能会发现它太大而不能成为一个理智的单线。我 99% 确定我会使用十几行来完成这项任务。您可以通过使用>seq1 行作为open 的两个参数形式的参数来稍微作弊,但这只是一个小问题。很大程度上取决于您希望代码有多健壮。
  • @JonathanLeffler 实际上,如果您使用$/ = "\n>",您可能很容易做到。 perl -lwe'$/="\n>"; while (<>) { open my $fh, ">", "file" . ++$i . ".txt" or die $!; print $fh $_; }' seq.txt
  • 嗯...不,这不太行,我现在明白了,好吧,也许可以调整一下。

标签: perl file split


【解决方案1】:

这是完成这项工作的一个相当简单的脚本:

use strict;
use warnings;
my $fh = *STDOUT;

while (<>)
{
    chomp;
    if (m/^>/)
    {
        close $fh;
        open $fh, $_ or die "Failed to open $_";
    }
    print $fh "$_\n";
}

my $fh = *STDOUT; 行表示如果第一行 &gt;file 之前有内容,则将其回显到标准输出。

以此为基础,您可以决定将其展平为一行,忽略错误、关闭打开的文件、限制和可读性:

perl -e 'while(<>){chomp;open$f,$_ if(m/^>/);print$f "$_\n";}'

不过,我不可能建议这样做。 (是的,两个空格都是必需的。)

【讨论】:

  • perl -e'while(&lt;&gt;) { ... } 又名perl -ne'...'chomp; ... print "$_\n" 又名 perl -lperl -nle'if (/^&gt;/) { open $fh, $_; } print $fh $_; '
  • 通过这样做甚至可以静默无害地依赖打开失败:perl -ple'open STDOUT, $_'
  • 对不起,我不明白你的意思。它的格式与您的单线完全相同。即便如此,我还是在答案中添加了它,以便为解释腾出空间。这是我发现的一个非常奇怪的小功能,几乎值得一些混淆奖励。
  • 谢谢乔纳森,非常好的练习,谢谢你的回答:)
【解决方案2】:

看着Jonathan's answer,我想出了一些奇怪的东西来发布一个新的答案。我想补充一点,这应该被视为一个练习示例(也许是混淆),而不是任何正确的代码。该解决方案的全部功劳归于 Jonathan。此外,这是一个危险的解决方案,如底部所述。

perl -ple 'open STDOUT, $_' yourfile.txt

这依赖于以&gt;seq1 开头的行与Jonathan 发现的旧2 参数open 一起使用。例如。 open $fh, "&gt;seq1" 将创建(覆盖)并打开文件seq1 进行写入。

同时,任何没有有效“模式”符号的行——&lt;&gt;| 等——将默认打开以供阅读,如果我们赌事实上,该目录中不存在名称为 123 234 56 等的文件,我们可以依靠 open 静默失败并保持之前打开的 STDOUT 文件句柄。

通过使用-l 选项,我们不需要chomp $_ 这样open 就不会失败,我们也不需要在打印中添加换行符。同时,-p 选项将负责创建while 循环并进行打印。

因为默认打印到STDOUT,所以我们需要做的就是重新打开STDOUT文件句柄,剩下的由输入文件的内容处理。

这个单线的完整代码,用cmets表示哪些部分来自哪个switch:

BEGIN { $/ = "\n"; $\ = "\n"; }    # -l, gives newlines to print
while (<>) {                       # -p 
    chomp $_;                      # -l
    open STDOUT, $_;               # our code
}
continue {
    print STDOUT $_;               # -p
}

注意:此代码将释放open 命令的全部功能,这很危险,在这种情况下,允许在您的文件系统上执行任意命令。这是允许使用 2 参数 open 的副作用。

【讨论】:

  • 谢谢!不知道 -l 选项以及它如何让我们大吃一惊。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-31
  • 1970-01-01
  • 1970-01-01
  • 2015-08-19
  • 2016-11-22
  • 2014-05-08
  • 2014-03-19
相关资源
最近更新 更多