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



所以我需要将大文本文件中的特定行更改为之前找到的一行。文本的外观:

名称:一些文本

Société:一些文本 地址:一些文本

和numb3rs 邮政编码: [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是邮政编码后的前两位数字:。
尚未起作用的是最后一个sed位:我希望结束文件看起来像旧文件,只是将"Tél."部分更改为$dept.
新文件:

名称:一些文本

Société:一些文本 地址:一些文本

和numb3rs 邮政编码:90000 一些文本
90
个数字 传真:
数字

"----------------------">

显然,这种带有名称的模式重复,但有时 Tél. 和下面的行不存在。

TL博士;我想更改文件中的模式,找到一行的东西,找到一行的东西发生变化。

如果您找到一种不同的方法来获得$dept不同的行,我将很高兴听到它。

我知道我的代码不是最高效的,但我一周前才了解 sed。

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

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

名称:约翰·多伊 社会:APERTURE SCIENCE 地址:巴黎街 37 号 CS 30112 邮政编码:51726 兰斯 CEDEX 电话:12 34 56 78 90 传真:12 34 56 78 90"----------------------">





名称:



奥利弗·特威斯特
法国兴业银行: 美国宇航局地址:
40 RUE DU GINGEMBRE CS 70999 邮政编码: 67009 斯特拉斯堡 CEDEX 电话:12 34

56 78 90 传真:

12 34 56 78 90
"----------------------">
标称: 巴拉克·奥巴马
法国兴业银行: 白宫地址:
124 戴高乐大道 邮政编码: 75017 巴黎
电信 : 12 34 56 78 90
"----------------------">

我想要实现的输出:

名称:约翰·多伊
法国兴业银行:巴黎街 37 号 CS 30112 邮政编码:
51726 兰斯 CEDEX 51 12 34 56 78 90


传真:
12 34 56 78 90
"----------------------">
名称:奥利弗·特威斯特
法国公司:美国宇航局地址:
40 RUE DU GINGEMBRE CS 70999 邮政编码:67009 斯特拉斯堡CEDEX
67 12 34 56 78 90
传真:
12 34 56 78 90
"----------------------">
名称:巴拉克·奥巴马
社会:白宫
地址:戴高乐大道124号 邮编:75017 巴黎
75 12 34 56 78 90
"----------------------">

使用 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

请注意,部门编号将在"OLIVER TWIST"块中的一行上输出(因为 Tél.: 与第一个块一样在一行上)

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

/Code Postal:/ {
match($0, /Code Postal: *([0-9][0-9])/, result);
dept = result[1];
}
/^Tél/ { $2 = dept }
{ print }

将代码保存到文件,然后调用awk -f file input_file。它的工作原理是这样的:如果行与"Code Postal"匹配,则将邮政编码的前两位数字保存在变量dept中。如果该行以"Tél"开头,请将第二个字段替换为值dept。然后,打印任何行。

这是我对您要完成的目标的猜测。

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跳过脚本的其余部分,因此我们仅在第二个文件中打印。结果输出应该(希望!)是您需要的结果。

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

听起来这可能是你想要的,使用 GNU awk 作为第三个 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] 中,并在打印该行和任何其他不以Tél开头的行之前将前面的换行符 (ORS) 添加到当前行的末尾。

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

相关内容

  • 没有找到相关文章

最新更新