我有一个这样的文件
A1: abc.com B1: Hi there
B1: Your Test mail A1: gml.com
B1: Your new mail A1: hml.com
A1: def.com B1: Test email
B1: hello world A1: yml.com
我想始终先选择零件,A1: <string>
然后再选择B1: <string>
零件。
我已经尝试过grep
并awk
喜欢下面的
grep -Po '(?<=A1:)\W*\K[^ ]*' file.txt
awk -F"A1:|B1:" '{print $1 $2}' file.txt
但他们没有给出确切的结果
我希望输出是这样的:
A1: abc.com B1: Hi there
A1: gml.com B1: Your Test mail
A1: hml.com B1: Your new mail
A1: def.com B1: Test email
A1: yml.com B1: hello world
答案1
您可以保留以原样开头的行A1
,并重新排列以B1
# if -E or -r is not supported: sed 's/\(B1:.*\)\(A1:.*\)/\2 \1/' ip.txt
$ sed -E 's/(B1:.*)(A1:.*)/\2 \1/' ip.txt
A1: abc.com B1: Hi there
A1: gml.com B1: Your Test mail
A1: hml.com B1: Your new mail
A1: def.com B1: Test email
A1: yml.com B1: hello world
.*
是贪婪的,所以这个解决方案假设A1:
和B1:
在每一行中都是唯一的(B1:.*)(A1:.*)
是两个捕获组 - 为了满足整个表达式,第一个捕获组将捕获从B1:
up 到 before 的所有字符串A1:
。第二个将从A1:
行尾开始捕获字符串\2 \1
重新排列捕获的字符串,中间留有空格- 进一步阅读:https://www.gnu.org/software/sed/manual/sed.html#Back_002dreferences-and-Subexpressions
和awk
$ awk -F'A1:' '{print $1 ~ /B1:/ ? FS $2 " " $1 : $0}' ip.txt
A1: abc.com B1: Hi there
A1: gml.com B1: Your Test mail
A1: hml.com B1: Your new mail
A1: def.com B1: Test email
A1: yml.com B1: hello world
如果第一个字段包含B1:
,则重新排列字段,否则按原样打印输入行
答案2
我们可以使用以下方法来做到这一点:
perl -F'/(A1:|B1:)/' -lane '
my %h = @F[1..$#F];
print map { "$_$h{$_} " } qw/A1: B1:/;
' input.txt
输出:
A1: gml.com B1: Your Test mail
A1: abc.com B1: Hi there
A1: hml.com B1: Your new mail
A1: def.com B1: Test email
A1: yml.com B1: hello world
解释:
- 拆分 A1: 和/或 B1: 上的每条记录,并且还包括“拆分器”。
- @F 数组中的第一个字段应被忽略。因此,@F 数组中有偶数个元素,然后将其存储为散列 %h,键为“A1:”和“B1:”。
- 现在,我们通过匿名数组 qw/.../ 迭代指定的顺序,并将结果打印到 stdout。