一旦你需要开始跟踪状态(例如,我在文件中的什么位置?到目前为止我看到了什么?),我通常会从 sed 切换到 perl。这是一个简单的单行代码来完成您需要的操作(将“NEW CODE”替换为您需要插入的新代码;替换<filename>
为实际文件):
perl -ne 'BEGIN{$state=0} print; if (/^\s*start\(\){/) {$state++;} if (/if mountpart "\$1" \/mnt -w ; then/) { if ($state==1) {print "NEW CODE\n"; $state++;} }' <filename>
简单分解一下: -n
让 perl 工作起来有点像 sed;它会读取每一行并处理它,但是,除非你要求它,否则它不会打印该行;这让我们在(可能)输出新代码之前输出每一行。 -e
使 perl 从命令行读取程序。获取程序并重新格式化它,并添加注释,我们得到:
// -n runs the program for every line of input
// but a BEGIN {} block only runs once, before input
BEGIN {
//where are we in the input?
// 0=no start() yet
// 1=start() was seen
// 2=we have output the new code; never do it again
$state=0
}
print; // print the line we just read in, unchanged
if (/^\s*start\(\){/) { //regex. Did we see start(){ ?
$state++; //if so, change to next state
}
if (/if mountpart "\$1" \/mnt -w ; then/) { //regex. did we see mountpart cmd?
if ($state==1) { //if so, are we in the right state
print "NEW CODE\n"; //if so, output the new code
$state++; //...and change to next state
//...so we don't output new code 2x
}
}
请注意,我们从不按名称引用该行......我们只是说“打印”来打印该行,并且正则表达式看起来像 sed 模式,我们假设我们正在匹配该行。这是因为-n
将每一行读入 perl 的$_
变量,这是 print 等函数的默认参数。这不是我编写大型 perl 程序的方式,但对于像这样的单行或简短的一次性修复脚本来说是合适的(并且是惯用的)。
您也可以<filename>
像 sed 一样省略和流式传输输入,例如:
cat myfile.txt | perl -ne 'BEGIN...'