使用sed转到特定行,更改模式然后在行和另一个模式之间打印

时间:2016-05-27 14:28:34

标签: bash sed debian gnu

所以我需要通过之前找到的内容更改大文本文件中的特定行。文字是什么样的:

  

Nom:有些文字
  Société:一些文字
  Adresse:一些文字和麻木代码邮编:[0-9] [0-9] [0-9] [0-9] [0-9]有些文字
  联系电话。 :
  数字
  传真:
  数字
  “----------------------”

到目前为止我发现的是(我相信我差不多完成了):

K=0
while [ $K -lt 11519 ]; do
    let K=K+1
    L=`head -n $K file_that_contains_line_numbers_I_want.txt | tail -1`
    M=`expr $L - 2`
    dept=`head -n $L filename.txt | tail -1 | sed -e 's/Adresse:.*Code Postal: //' -e 's/[0-9]\{3\} .*//'`
    sed -n ""$M"{s/Tél. :/$dept/; /----------------------/p; q}" filename.txt >>newfile.csv
done

其中$ dept是Code Postal之后的前两位数。: 什么还没有工作是最后一个sed位:我希望结束文件看起来像旧文件,只是使用“Tél”。部分改为$ dept。
新文件:

  

Nom:有些文字
  Société:一些文字
  Adresse:some text and numb3rs Code Postal:90000 SOME TEXT
  90个
  数字
  传真:
  数字
  “----------------------”

显然这个模式的名称重复,但有时候是Tél的行。以下不在那里。

是的;博士;我想用一个找到一行的东西来改变一个文件中的模式,发现一个行更改了。

如果你找到一种不同的方式让$ dept在另一条线上,我会很高兴听到它。

我知道我的代码并不是最有效的代码,但我只在一周前了解了sed。

提前感谢您帮助我/纠正我。

编辑:由于我被要求提供一些输入,这里是:

  

Nom:JOHN DOE
  Société:APERTURE SCIENCE
  Adresse:37 RUE OF PARIS CS 30112代码邮政:51726 REIMS CEDEX
  联系电话。 :
  12 34 56 78 90
  传真:
  12 34 56 78 90
  “----------------------”
  Nom:OLIVER TWIST
  Société:NASA
  地址:40 RUE DU GINGEMBRE CS 70999代码邮编:67009 STRASBOURG CEDEX
  联系电话。 :
  12 34 56 78 90
  传真:
  12 34 56 78 90
  “----------------------”
  Nom:BARACK OBAMA
  Société:WHITE HOUSE
  Adresse:124 BOULEVARD DE GAULLE代码邮政:75017 PARIS
  联系电话。 :   12 34 56 78 90
  “----------------------”

我希望实现的输出:

  

Nom:JOHN DOE
  Société:APERTURE SCIENCE
  Adresse:37 RUE OF PARIS CS 30112代码邮政:51726 REIMS CEDEX
  51个
  12 34 56 78 90
  传真:
  12 34 56 78 90
  “----------------------”
  Nom:OLIVER TWIST
  Société:NASA
  地址:40 RUE DU GINGEMBRE CS 70999代码邮编:67009 STRASBOURG CEDEX
  67   12 34 56 78 90
  传真:
  12 34 56 78 90
  “----------------------”
  Nom:BARACK OBAMA
  Société:WHITE HOUSE
  Adresse:124 BOULEVARD DE GAULLE代码邮政:75017 PARIS
  75   12 34 56 78 90
  “----------------------”

4 个答案:

答案 0 :(得分:1)

使用sed:

$ sed '/.*Code Postal: \([0-9][0-9]\).*/{p;s//\1/;n;d}' file
Nom: some text
Société: some text
Adresse: some text and numb3rs Code Postal: 90000 SOME TEXT
90
numbers
Fax :
numbers
"----------------------"
  • /.*Code Postal: \([0-9][0-9]\).*/:搜索包含Code Postal:后跟两位数
  • 的行
  • p:打印匹配行(即克隆包含“Code Postal”的行)
  • s//\1/:将匹配的行(s//\1)替换为捕获的数字(\([0-9][0-9]\)
  • n阅读下一行(“Tél”)并删除它(d

我刚看到你的编辑,你可以通过以下方式实现:

sed '/.*Code Postal: \([0-9][0-9]\).*/{p;s//\1/;N;/[0-9]/s/\n/ /;s/Tél\. : *//}' file

请注意,dept编号将在“OLIVER TWIST”块中的单行输出(因为Tél:与第一个块一样在一行上)

答案 1 :(得分:0)

您不提供要检查的示例输入,但这应该有效:

awk -f file input_file

将代码保存到文件中,然后调用dept。它的工作方式如下:如果该行与“Code Postal”匹配,则将邮政编码的前两位保存在变量dept中。如果该行以“Tél”开头,则将第二个字段替换为 let printCompletionHandler: UIPrintInteractionCompletionHandler = { (controller, success, error) -> Void in if success { // Printed successfully // Remove file here ... } else { // Printing failed, report error ... } } if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Pad { printController.presentFromRect(self.printButton.frame, inView: self.view, animated: true, completionHandler: printCompletionHandler) } else { printController.presentAnimated(true, completionHandler: printCompletionHandler) } 的值。然后,打印任何一行。

答案 2 :(得分:0)

这是我对你想要完成的事情的猜测。

awk 'NR==FNR { # Store line numbers in a[]
    a[$1] = $1; next }
   FNR in a { m=1 } # We are in match range
   /^------$/ { m=0 }  # Separator: we are out of range
   m && /^Adresse.*Code postal:/ { c=substr($NF, 1, 2); $NF = 90000 }
   m && /^Tél\. :$/ { $0 = c }
   { print }' file_that_contains_line_numbers_I_want.txt filename > filename.new

这包含一些常见的Awk习语。以下是人类术语中的一个非常简短的草图。

NR是当前行号,FNR是当前文件中的文件号。当它们相等时,表示您正在读取第一个输入文件。在这种情况下,我们将行号读入数组a并跳到下一行。

如果我们失败了,我们正在阅读第二个文件。当我们看到a中存在的行号时,我们将标志m设置为真(非零)值,以指示我们处于应该发生替换的区域。当我们看到虚线时,我们清除它,因为这标志着当前记录的结束。

最后,如果我们在其中一个目标记录中(m为真),我们会查找模式并执行请求的提取和替换。 NF是当前行中的字段数,$选择一个字段,因此$NF = 90000替换该行的最后一个字段;并且$0是整个输入行,因此当我们看到Tél. :时,我们会用提取的代码替换整行。

在剧本结束时,我们打印正在阅读的内容;第一个块中的next会跳过脚本的其余部分,因此我们只在第二个文件中打印时才打印。结果输出应该(希望!)是你需要的结果。

这应该比一遍又一遍地读取同一个文件快几个数量级,并且只要第一个文件包含少于几百万个行号就应该工作(假设现代硬件;如果你有一个非常小的机器有限记忆和没有交换,也许成千上万。)

答案 3 :(得分:0)

听起来这可能是你想要的,使用GNU awk为第3个arg匹配()):

$ awk 'match($0,/.*Code Postal: *([0-9][0-9])/,a){$0=$0 ORS a[1]} !/^Tél/' file

或gawk或mawk for gensub():

$ awk '{$0=gensub(/.*Code Postal: *([0-9][0-9]).*/,"&\n\\1",1)} !/^Tél/' file
Nom: some text
Société: some text
Adresse: some text and numb3rs Code Postal: 90000 SOME TEXT
90
numbers
Fax :
numbers
"----------------------"

以上内容在此输入文件上运行:

$ cat file
Nom: some text
Société: some text
Adresse: some text and numb3rs Code Postal: 90000 SOME TEXT
Tél. :
numbers
Fax :
numbers
"----------------------"

以上匹配所述的正则表达式,将捕获的2个数字保存在数组a [1]中,并在打印之前将新行(ORS)前面的行添加到当前行的末尾,以及任何其他不行的行。从Tél开始。

如果您要在UNIX中进行任何文本操作,请阅读Arnold Robbins撰写的第4版Awk有效编程。