使用 sed 转到特定行,更改模式然后打印行和另一个模式之间的所有内容
Using sed to go to a specific line, change pattern then print all between line and another pattern
所以我需要用在前一行找到的内容来更改大文本文件中的特定行。文字的样子:
Nom: some text
Société: some text
Adresse: some text and numb3rs Code Postal: [0-9][0-9][0-9][0-9][0-9] SOME TEXT
Tél. :
numbers
Fax :
numbers
"----------------------"
到目前为止我发现的是(我相信我快完成了):
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.
新文件:
Nom: some text
Société: some text
Adresse: some text and numb3rs Code Postal: 90000 SOME TEXT
90
numbers
Fax :
numbers
"----------------------"
显然这个模式的名称重复,但有时线条 Tél。以下不存在。
tl 博士;我想改变一个文件中的模式,找到一行的东西,找到一行的东西改变。
如果您找到在不同行中获取 $dept 的不同方法,我将非常高兴听到。
我知道我的代码不是最高效的,但我在一周前才了解 sed。
在此先感谢您帮助 me/correcting 我。
编辑:我被要求提供一些意见,这里是:
Nom: JOHN DOE
Société: APERTURE SCIENCE
Adresse: 37 RUE OF PARIS CS 30112 Code Postal: 51726 REIMS CEDEX
Tél. :
12 34 56 78 90
Fax :
12 34 56 78 90
"----------------------"
Nom: OLIVER TWIST
Société: NASA
Adresse: 40 RUE DU GINGEMBRE CS 70999 Code Postal: 67009 STRASBOURG CEDEX
Tél. :
12 34 56 78 90
Fax :
12 34 56 78 90
"----------------------"
Nom: BARACK OBAMA
Société: WHITE HOUSE
Adresse: 124 BOULEVARD DE GAULLE Code Postal: 75017 PARIS
Tél. :
12 34 56 78 90
"----------------------"
我想要实现的输出:
Nom: JOHN DOE
Société: APERTURE SCIENCE
Adresse: 37 RUE OF PARIS CS 30112 Code Postal: 51726 REIMS CEDEX
51
12 34 56 78 90
Fax :
12 34 56 78 90
"----------------------"
Nom: OLIVER TWIST
Société: NASA
Adresse: 40 RUE DU GINGEMBRE CS 70999 Code Postal: 67009 STRASBOURG CEDEX
67
12 34 56 78 90
Fax :
12 34 56 78 90
"----------------------"
Nom: BARACK OBAMA
Société: WHITE HOUSE
Adresse: 124 BOULEVARD DE GAULLE Code Postal: 75017 PARIS
75
12 34 56 78 90
"----------------------"
您没有提供示例输入以供检查,但这应该有效:
/Code Postal:/ {
match([=10=], /Code Postal: *([0-9][0-9])/, result);
dept = result[1];
}
/^Tél/ { = dept }
{ print }
将代码保存到文件中,然后调用 awk -f file input_file
。它是这样工作的:如果该行匹配 "Code Postal",则将邮政编码的前两位保存在变量 dept
中。如果该行以 "Tél" 开头,请将第二个字段替换为 dept
的值。然后,打印任意一行。
这是我对您要完成的目标的猜测。
awk 'NR==FNR { # Store line numbers in a[]
a[] = ; 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\. :$/ { [=10=] = c }
{ print }' file_that_contains_line_numbers_I_want.txt filename > filename.new
这包含一些常见的 Awk 习语。以下是一个非常简短的脚本草图。
NR
是当前总行号,FNR
是当前文件中的文件号。当它们相等时,意味着您正在读取第一个输入文件。在这种情况下,我们将行号读入数组 a
并跳到下一行。
如果我们失败了,我们正在读取第二个文件。当我们看到 a
中出现的行号时,我们将标志 m
设置为真(非零)值以指示我们处于应该进行替换的区域中。当我们看到虚线时,我们将其清除,因为这标志着当前记录的结束。
最后,如果我们在其中一个目标记录中(m
为真),我们将查找模式并执行请求的提取和替换。 NF
是当前行的字段数,$
选择一个字段,所以$NF = 90000
替换该行的最后一个字段; [=20=]
是整个输入行,所以当我们看到 Tél. :
时,我们用提取的代码替换整行。
在脚本的末尾,我们打印正在阅读的内容;第一个块中的 next
跳过脚本的其余部分,因此我们仅在第二个文件中时才打印。结果输出应该(希望!)是您需要的结果。
这应该比一遍又一遍地读取同一个文件快几个数量级,并且只要第一个文件包含的行号少于数百万(假设是现代硬件;如果你有一台非常小的机器)内存有限且没有交换空间,可能有数万个)。
使用 sed :
$ sed '/.*Code Postal: \([0-9][0-9]\).*/{p;s///;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///
: 用捕获的数字 (\([0-9][0-9]\)
) 替换匹配行 (s//
)
n
读取下一行 ("Tél") 并将其删除 (d
)
我刚看到您的编辑,您可以通过以下方式实现:
sed '/.*Code Postal: \([0-9][0-9]\).*/{p;s///;N;/[0-9]/s/\n/ /;s/Tél\. : *//}' file
请注意,部门编号将在 "OLIVER TWIST" 块中输出在单行上(因为 Tél.: 与第一个块一样在单行上)
听起来这可能就是您想要的,使用 GNU awk 作为第三个参数来匹配 ()):
$ awk 'match([=10=],/.*Code Postal: *([0-9][0-9])/,a){[=10=]=[=10=] ORS a[1]} !/^Tél/' file
或 gensub() 的 gawk 或 mawk:
$ awk '{[=11=]=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 撰写的 Effective Awk programming,第 4 版。
所以我需要用在前一行找到的内容来更改大文本文件中的特定行。文字的样子:
Nom: some text
Société: some text
Adresse: some text and numb3rs Code Postal: [0-9][0-9][0-9][0-9][0-9] SOME TEXT
Tél. :
numbers
Fax :
numbers
"----------------------"
到目前为止我发现的是(我相信我快完成了):
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.
新文件:
Nom: some text
Société: some text
Adresse: some text and numb3rs Code Postal: 90000 SOME TEXT
90
numbers
Fax :
numbers
"----------------------"
显然这个模式的名称重复,但有时线条 Tél。以下不存在。
tl 博士;我想改变一个文件中的模式,找到一行的东西,找到一行的东西改变。
如果您找到在不同行中获取 $dept 的不同方法,我将非常高兴听到。
我知道我的代码不是最高效的,但我在一周前才了解 sed。
在此先感谢您帮助 me/correcting 我。
编辑:我被要求提供一些意见,这里是:
Nom: JOHN DOE
Société: APERTURE SCIENCE
Adresse: 37 RUE OF PARIS CS 30112 Code Postal: 51726 REIMS CEDEX
Tél. :
12 34 56 78 90
Fax :
12 34 56 78 90
"----------------------"
Nom: OLIVER TWIST
Société: NASA
Adresse: 40 RUE DU GINGEMBRE CS 70999 Code Postal: 67009 STRASBOURG CEDEX
Tél. :
12 34 56 78 90
Fax :
12 34 56 78 90
"----------------------"
Nom: BARACK OBAMA
Société: WHITE HOUSE
Adresse: 124 BOULEVARD DE GAULLE Code Postal: 75017 PARIS
Tél. : 12 34 56 78 90
"----------------------"
我想要实现的输出:
Nom: JOHN DOE
Société: APERTURE SCIENCE
Adresse: 37 RUE OF PARIS CS 30112 Code Postal: 51726 REIMS CEDEX
51
12 34 56 78 90
Fax :
12 34 56 78 90
"----------------------"
Nom: OLIVER TWIST
Société: NASA
Adresse: 40 RUE DU GINGEMBRE CS 70999 Code Postal: 67009 STRASBOURG CEDEX
67 12 34 56 78 90
Fax :
12 34 56 78 90
"----------------------"
Nom: BARACK OBAMA
Société: WHITE HOUSE
Adresse: 124 BOULEVARD DE GAULLE Code Postal: 75017 PARIS
75 12 34 56 78 90
"----------------------"
您没有提供示例输入以供检查,但这应该有效:
/Code Postal:/ {
match([=10=], /Code Postal: *([0-9][0-9])/, result);
dept = result[1];
}
/^Tél/ { = dept }
{ print }
将代码保存到文件中,然后调用 awk -f file input_file
。它是这样工作的:如果该行匹配 "Code Postal",则将邮政编码的前两位保存在变量 dept
中。如果该行以 "Tél" 开头,请将第二个字段替换为 dept
的值。然后,打印任意一行。
这是我对您要完成的目标的猜测。
awk 'NR==FNR { # Store line numbers in a[]
a[] = ; 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\. :$/ { [=10=] = c }
{ print }' file_that_contains_line_numbers_I_want.txt filename > filename.new
这包含一些常见的 Awk 习语。以下是一个非常简短的脚本草图。
NR
是当前总行号,FNR
是当前文件中的文件号。当它们相等时,意味着您正在读取第一个输入文件。在这种情况下,我们将行号读入数组 a
并跳到下一行。
如果我们失败了,我们正在读取第二个文件。当我们看到 a
中出现的行号时,我们将标志 m
设置为真(非零)值以指示我们处于应该进行替换的区域中。当我们看到虚线时,我们将其清除,因为这标志着当前记录的结束。
最后,如果我们在其中一个目标记录中(m
为真),我们将查找模式并执行请求的提取和替换。 NF
是当前行的字段数,$
选择一个字段,所以$NF = 90000
替换该行的最后一个字段; [=20=]
是整个输入行,所以当我们看到 Tél. :
时,我们用提取的代码替换整行。
在脚本的末尾,我们打印正在阅读的内容;第一个块中的 next
跳过脚本的其余部分,因此我们仅在第二个文件中时才打印。结果输出应该(希望!)是您需要的结果。
这应该比一遍又一遍地读取同一个文件快几个数量级,并且只要第一个文件包含的行号少于数百万(假设是现代硬件;如果你有一台非常小的机器)内存有限且没有交换空间,可能有数万个)。
使用 sed :
$ sed '/.*Code Postal: \([0-9][0-9]\).*/{p;s///;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///
: 用捕获的数字 (\([0-9][0-9]\)
) 替换匹配行 (n
读取下一行 ("Tél") 并将其删除 (d
)
s//
)
我刚看到您的编辑,您可以通过以下方式实现:
sed '/.*Code Postal: \([0-9][0-9]\).*/{p;s///;N;/[0-9]/s/\n/ /;s/Tél\. : *//}' file
请注意,部门编号将在 "OLIVER TWIST" 块中输出在单行上(因为 Tél.: 与第一个块一样在单行上)
听起来这可能就是您想要的,使用 GNU awk 作为第三个参数来匹配 ()):
$ awk 'match([=10=],/.*Code Postal: *([0-9][0-9])/,a){[=10=]=[=10=] ORS a[1]} !/^Tél/' file
或 gensub() 的 gawk 或 mawk:
$ awk '{[=11=]=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 撰写的 Effective Awk programming,第 4 版。