【问题标题】:Perl, sed, or awk one-liner to change the format of the filePerl、sed 或 awk 单行更改文件格式
【发布时间】:2012-04-17 09:58:52
【问题描述】:

我需要有关如何更改以下格式的文件的建议 文件1:

A       504688
B       jobnameA
A       504690
B       jobnameB
A       504691
B       jobnameC
...

进入文件2:

A       B
504688  jobnameA
504690  jobnameB
504691  jobnameC
...

我能想到的一个解决方案是:

cat file1 | perl -0777 -p -e 's/\s+B/\t/' | awk '{print $2"\t"$3}'.

但我想知道是否有更有效的方法或已知的做法可以完成这项工作。

【问题讨论】:

  • 非常感谢垫子。我最近加入了社区。我会这样做的

标签: regex perl unix sed awk


【解决方案1】:
awk '/^A/{num=$2}/^B/{print num,$2}' file

或者,或者,

awk '{num=$2;getline;print num,$2}' file

【讨论】:

    【解决方案2】:
     perl -nawe 'print "@F[1 .. $#F]", $F[0] eq "A" ? "\t" : "\n"' < /tmp/ab
    

    perlrun 中查找选项。

    另一个有用的添加是-l(附加换行符以打印),但在这种情况下不是。

    【讨论】:

    • @briandfoy - 谢谢 - 但它实际上只是一个单行。请放心,我确实阅读了your book! :) 我强烈推荐它!
    • 感谢您的回答!顺便说一句,真的需要最后的“ 用于指导输出..
    • &lt; 是用于标准输入 (STDIN) 重定向的 shell 语法(Bash 和 UNIX 上的其他语法,以及 cmd.exe/Windows)。所以在这种情况下,标准输入来自文件。要了解为什么它在没有此输入重定向运算符的情况下在 Perl 中工作,请阅读 &lt;ARGV&gt; filehandle
    • 感谢您的详尽解释!
    【解决方案3】:

    这是一个 sed 解决方案:

    sed -e 'N' -e 's/A\s*\(.*\)\nB\s*\(.*\)/\1\t\2/' file
    

    此版本还将在顶部打印标题:

    sed '1{h;s/.*/A\tB/p;g};N;s/A\s*\(.*\)\nB\s*\(.*\)/\1\t\2/' file
    

    或者替代方案:

    sed -n '/^A\s*/{s///;h};/^B\s*/{s///;H;g;s/\n/\t/p}' file
    

    如果您的 sed 不支持将分号作为替代命令分隔符:

    sed -n '
    /^A\s*/{       # if the line starts with "A"
    s///             # remove the "A" and the whitespace
    h                # copy the remainder into the hold space
    }              # end if
    /^B\s*/{       # if the line starts with "B"
    s///             # remove the "B" and the whitespace 
    H                # append pattern space to hold space
    g                # copy hold space to pattern space
    s/\n/\t/p        # replace newline with tab and print
    }' file
    

    此版本还将在顶部打印标题:

    sed -n '/^A\s*/{s///;h;1s/.*/A\tB/p};/^B\s*/{s///;H;g;s/\n/\t/p}' file
    

    【讨论】:

      【解决方案4】:

      这适用于任何标题文本,而不仅仅是固定的 AB >>

      awk '{a=$1;b=$2;getline;if(c!=1){print a,$1;c=1};print b,$2}' file1 >file2
      

      ...它还会打印标题行

      如果你需要\t分隔符,那么使用:

      awk '{a=$1;b=$2;getline;if(c!=1){print a"\t"$1;c=1};print b"\t"$2}' file1 >file2
      

      【讨论】:

        【解决方案5】:

        假设您的输入文件是制表符分隔的:

        echo $'A\tB'
        cut -f2 filename | paste - -
        

        应该很快,因为这正是 cutpaste 的目的。

        【讨论】:

        • +1 - pastejoin 从未真正将其纳入我的永久心理工具集,但这可能是机器效率最高的解决方案。空格分隔文件的变体:cut -b8- /tmp/ab | paste - -
        • 哇...这非常优雅。你能解释一下 - 选项在粘贴命令中的作用吗? cygwin 手册页似乎并不明确。而且它是否灵活?意思是我可以提供更多选项,例如粘贴(转置)下面的 2 行吗?
        • 参见man.cx/paste -- 'paste' 将文件名作为参数并加入相应的行。如果“-”作为文件名给出,则从标准输入读取该文件的行。由于该命令中有 2 个破折号,因此将为“文件 1”读取一行,为“文件 2”读取另一行,直到消耗完所有输入。
        • 这非常整洁。感谢您的清晰解释。
        【解决方案6】:

        这可能对你有用:

         sed -e '1i\A\tB' -e 'N;s/A\s*\(\S*\).*\nB\s*\(\S*\).*/\1\t\2/' file
        

        【讨论】:

          猜你喜欢
          • 2019-04-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-19
          • 2017-05-01
          • 2021-05-03
          相关资源
          最近更新 更多