我试图使标题尽可能具体,一个例子应该可以解决问题。
我有一个制表符分隔的文件,其中的行以1
to开头5
。这被视为一个块(每个块可以有多个4
和条目5
)。
- next
1
定义下一个块的开始,依此类推。 - 我的前缀总是在以 开头的行中
3
。我想在每个块的每一行的开头写下这个词。
任何有关如何解决此问题的想法将不胜感激。不一定是sed
,可以是awk
,但sed
会是首选。
- 输入文件示例
1 foo1 2 foo1 3 bar1 | Prefix block 1 4 foo1 5 foo1 1 foo2 2 foo2 3 bar2 | Prefix block 2 4 foo2 4 foo3 5 foo2 5 foo3
- 此输入示例所需的输出
bar1 1 foo1 bar1 2 foo1 bar1 3 bar1 bar1 4 foo1 bar1 5 foo1 bar2 1 foo2 bar2 2 foo2 bar2 3 bar2 bar2 4 foo2 bar2 4 foo3 bar2 5 foo2 bar2 5 foo3
答案1
在您的情况下,想到了两遍awk
解决方案(这意味着我们必须指定输入文件名两次作为命令行上的操作数)。它假设该行上的标记由 on 输入分隔\t
,并且也由 on 输出分隔\t
。
awk 'BEGIN{FS=OFS="\t"}
NR==FNR{if ($1=="3") pre[++i]=$2;next} $1=="1" {j++} {print pre[j],$0}' input input
在第一遍中,NR
(全局行计数器)等于FNR
(每个文件行计数器),pre
每次遇到第一个字段 ( $1
) 等于 的行时,我们都会用前缀填充数组3
。因此,pre
是“块号”和关联前缀之间的映射。除此之外,我们不打印任何内容并立即跳到下一行执行。
在第二遍中,j
每次找到“起始块”条件(第一个字段$1
等于1
)时,我们都会增加块计数器,并且对于所有行都在前面添加与块计数器相对应的前缀。
答案2
GNU sed在扩展正则表达式模式下运行-E
并关闭自动打印-n
,以便我们知道何时打印。
sed -En '
#--------------------------------
# printing the block in pattern space
#--------------------------------
/\n/{
s/.*\n(.*)/\1&/
P;/\n.*\n/D;$d;g
}
#--------------------------------
# collect block
#--------------------------------
:15
/^1/{
N;h
/\n5/!b15
#--------------------------------
# collect trailing 5 lines
#--------------------------------
:tail5
$bend
n
/^5/{H;$!btail5;}
#--------------------------------
# place block prefix @ eol
#--------------------------------
$!x;$g
:end
s/.*\n3\t([^\n]+)\n.*/\n&\n\1\t/
D; # take me to block print section
}
' file
结果:
bar1 1 foo1
bar1 2 foo1
bar1 3 bar1
bar1 4 foo1
bar1 5 foo1
bar2 1 foo2
bar2 2 foo2
bar2 3 bar2
bar2 4 foo2
bar2 4 foo3
bar2 5 foo2
bar2 5 foo3