2012-08-25 141 views
1

我被困在看起来应该对SED来说很简单的东西中。SED - 通过文件的其余部分删除第一行的出现

我有一些(类)的CSV文件,我从另一个应用程序中获得,所以我无法控制它的输出。一些预处理已经完成了SED,但是我被困在最后一个。因此,如果可能的话,我希望用SED来做,以避免使用第三个应用程序。

的问题是,该文件(第一行)的标题线沿文件重复,但遗憾的是具有以下特征:

  1. 每个CSV文件的标题是未知的先前。每个文件都有自己的标题,可能彼此不同;发生在每N行(为N固定的已知数量)
  2. 其他数据(非标题)线可能被重复
  3. 不总是重复,并应保持

因此,假设我有以下2档:

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 
+0

乔纳森,谢谢你的提示。没有足够的声望,但只要我得到它,我会标记为有用。我很长一段时间只读堆栈溢出风扇。我没想到会得到有用的答案,所以现在我是一个很大的SO粉丝。谢谢你们! – RFVoltolini

回答

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可能不需要这些限制中的一部分,但所显示的代码可能在任何地方都有效。

+0

+1我也是这么做的。如果第一行可能包含正则表达式元字符,它们将需要转义。 – tripleee

+0

工程就像一个魅力,也很快。一百万行文件(20MB)耗费了大约0.5秒的时间。 – RFVoltolini

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脚本从输入的第一行文件。

+0

谢谢potong。对于小文件,我猜这1行sed是最好的选择。但对于更大的文件,这可能会变得非常慢。一个100万行文件花了我10秒(20MB),而乔纳森替代方案花了0.5秒(请参阅接受的答案)。 – RFVoltolini

+0

@RFVoltolini:您的结果时间很有趣。 Potong的sed表达式必须复制每一行,扩展它,使用一个适度复杂的正则表达式(正则表达式中的'\ 1'使其变得复杂,至少在执行它时花费的时间),然后通常将扩展移除这条线,所以它比一个简单的正则表达式匹配慢并不令人惊讶。不过,我有点惊讶,它慢了20倍。不过,这是一个聪明的表达。 –

+0

@RFVoltolini请参阅编辑。 – potong

1

在情况下,如果你有兴趣在AWK:

​​
+0

或更简单地说:'NR == 1 {p = $ 0}; NR == 1 || p!= $ 0'。 – Thor

+0

或更简单地说'NR == 1 &&p=$0; p!= $ 0' – potong

+0

哇!小巧,快速,强大!我想我需要花一些时间来学习awk并重写我的洞脚本。 – RFVoltolini

相关问题