SED - 通过文件的其余部分删除第一行的出现

时间:2012-08-25 14:35:31

标签: csv sed text-files

我陷入了对SED来说应该很简单的事情。

我从其他应用程序获得了一些(某种)CSV文件,因此我无法控制其输出。一些预处理已经完成了SED,但是我被困在最后一个。所以我希望在可能的情况下使用SED来避免使用第三个应用程序。

问题是文件的标题行(第一行)沿着文件重复,但不幸的是具有以下特征:

  1. 以前未知每个CSV文件的标题。每个文件都有自己的标题,可能彼此不同;
  2. 并非总是在每N行发生重复(N是固定的已知数字)
  3. 可能会重复其他数据(非标题)行,并且应该维护
  4. 所以,假设我有以下两个文件:

    Cash.csv

    Name; Amount
    John; 3.55
    Erick; 4.76
    John; 8.99
    Name; Amount
    Erick; 4.76
    Mark; 1.00
    Name; Amount
    John; 3.55
    

    Check.csv

    Name; Account; Amount
    Erick; 345344; 123.00
    Mark; 88849; 323.50
    Name; Account; Amount
    John; 474473; 99.00
    Mark; 88849; 323.50
    Mark; 88849; 323.50
    John; 474473; 99.00
    

    我希望应用于每个文件的单个SED脚本将它们转换为:

    Cash.processed.csv

    Name; Amount
    John; 3.55
    Erick; 4.76
    John; 8.99
    Erick; 4.76
    Mark; 1.00
    John; 3.55
    

    Check.processed.csv

    Name; Account; Amount
    Erick; 345344; 123.00
    Mark; 88849; 323.50
    John; 474473; 99.00
    Mark; 88849; 323.50
    Mark; 88849; 323.50
    John; 474473; 99.00
    

    我想知道是否可以使用SED“保持缓冲区”作为删除命令的模式:

    1h     #Hold the first line (headings)
    /\h/d  #Use hold buffer as a pattern to delete
    

    假设“\ h”将保持缓冲区返回到删除命令。

    感谢您的回复;

    PS:请不要回答以下过度具体的命令:

    1p;/Name; Amount\|Name; Account; Amout/d
    

3 个答案:

答案 0 :(得分:4)

我认为您需要从一个sed命令中捕获第一行,然后在主操作命令中使用它:

line1=$(sed 1q $datafile)

sed -e "2,$ {/$line1/d;}" \
    -e '...rest of sed script...' $datafile

因为sed 1q在读取第一行后退出,所以无论数据文件有多大,它都会很快。如果第一行可能包含斜杠(可能是标题"Name/Number")或其他正则表达式元字符,那么请考虑使用类似的东西,用.替换所有斜杠:

line1=$(sed '1{s%/%.%g;q;}' $datafile)

我使用Mac OS X(10.8.1)版本的sed进行了一些操作,这比GNU sed更加模糊。在第二个(主要)sed命令中,匹配必须在{...}中,美元必须是分开的(或者shell对无效参数替换感到厌倦),并且需要使用分号。 GNU sed可能不需要其中一些限制,但显示的代码可能在任何地方都可以使用。

答案 1 :(得分:2)

这可能适合你(GNU sed):

sed '1h;1!{G;/^\(.*\)\n\1/d;s/\n.*//}' file

说明:

  • 1h将标题行存储在保留空间(HS)中并打印。
  • 1!{G;/^\(.*\)\n\1/d;s/\n.*//}对于除第一行之外的每一行,追加换行后跟HS的内容(即标题行)。将该行的第一部分与标题行进行比较,如果删除该行则相同。如果它没有删除附加的换行符和标题行并正常打印。

编辑:

对于大型文件来说确实非常慢,更快速且更容易理解的解决方案是:

sed 's|.*|1!{/^&$/d}|;q' file | sed -f - file

这会从输入文件的第一行创建一个sed脚本。

答案 2 :(得分:1)

如果您对awk感兴趣:

awk '{if(NR==1){p=$0;print}if(NR>1 && p!=$0)print}' your_file
相关问题