英文:
SED INSERT block of code BEFORE matched block
问题
INSERT BEFORE:
sed '/Categ #n/{N;N;s/Categ #n\nItemName 1/&\n**new_line1**\n**new_line2**\n**new_line3**/}' input.txt
APPEND AFTER:
sed '/ItemName 2/{N;s/\(ItemName 2\)\(.*\)/\n**new_line1**\n**new_line2**\n**new_line3**/}' input.txt
英文:
I have a text file I want to edit during a script excecution.
I want to pass from the text on left to the text on right using sed
insert:
INSERT BEFORE:
from:
[...]
[ placeholder ]
Categ #n
ItemName 1
[...]
[ placeholder ]
Categ #n
ItemName 2
[...]
to:
[...]
[ placeholder ]
Categ #n
ItemName 1
[...]
**new_line1** <<<--- INSERT BEFORE
**new_line2** |||
**new_line3** |||
[ placeholder ] <<<--- 3-lines match
Categ #n |||
ItemName 2 |||
[...]
I have tried to adapt sed append
lines to sed insert
.
The appending works, the insert does not.
The match to append was 2 lines one after the other.
In the insert, the match it is 3 lines and I tried to match the first and the last, as I don't know how to match the entire 3-lines block.
APPEND AFTER:
sed -e '/^\[ placeholder \]\/ItemName 2/a \\nnew_line1\nnew_line2\nnew_line3' input.txt
and it works from:
[...]
[ placeholder ]
ItemName 1
[...]
[ placeholder ]
ItemName 2
[...]
to:
[...]
[ placeholder ]
ItemName 1
[...]
[ placeholder ] <<<--- 2-lines match
ItemName 2 |||
**new_line1** <<<--- APPENDED AFTER
**new_line2** |||
**new_line3** |||
[...]
I have tried to use the syntax examples in this post, but with no success.
The sed - Stream Editor
答案1
得分: 0
问题会变得简单得多,如果文件是倒着读的。
可以使用sed
解决方案,但awk
非常直观:
tac input.txt |
awk '
# 将每一行输入复制到输出
{ print }
# 查找所需的项目名称行
# 如果找到,改变状态并跳过剩余的测试(无法匹配)
$1=="ItemName" && $2==2 { s = 1; next }
# 如果我们到达这里,查找占位符行
# 如果找到,追加新行并重置状态
s && /\[ placeholder \]/ {
print "new3"
print "new2"
print "new1"
s = 0
}
' | tac > output.txt
英文:
The problem becomes much simpler if the file is read backwards.
A sed
solution is possible but awk
is very straightforward:
tac input.txt |
awk '
# copy every input line to output
{ print }
# look for desired itemname line
# if found, change state and
# skip remaining tests (which can't match)
$1=="ItemName" && $2==2 { s = 1; next }
# if we get here, look for placeholder line
# if found, append new lines and reset state
s && /\[ placeholder \]/ {
print "new3"
print "new2"
print "new1"
s = 0
}
' | tac > output.txt
答案2
得分: 0
如果您的输入中不包含NUL
字节,您可以尝试使用GNU sed
执行以下操作:
$ from='[ 占位符 ]\nCateg #n\nItemName 2\n'
$ to='**新行1**\n**新行2**\n**新行3**\n'
$ sed -Ez "s/(^|\n)($from)/$to/" input.txt
[...]
[ 占位符 ]
Categ #n
ItemName 1
[...]
**新行1**
**新行2**
**新行3**
[ 占位符 ]
Categ #n
ItemName 2
[...]
使用-z
选项将输入视为一组以零字节(ASCII NUL
字符)终止的行,而不是以换行符终止。如果输入不包含NUL
字节,这将允许一次性处理整个文件。当然,您必须正确转义from
和to
中的特殊字符。
英文:
If your input does not contain NUL
bytes you could try the following with GNU sed
:
$ from='\[ placeholder \]\nCateg #n\nItemName 2\n'
$ to='**new_line1**\n**new_line2**\n**new_line3**\n'
$ sed -Ez "s/(^|\n)($from)/$to/" input.txt
[...]
[ placeholder ]
Categ #n
ItemName 1
[...]
**new_line1**
**new_line2**
**new_line3**
[ placeholder ]
Categ #n
ItemName 2
[...]
With the -z
option the input is treated as a set of lines, each terminated by a zero byte (the ASCII NUL
character) instead of a newline. If the input does not contain NUL
bytes this allows to process the entire file at once. Of course you must properly escape special characters in from
and to
.
答案3
得分: 0
以下是已翻译的代码部分:
A loop probably makes sense to accumulate the block into the pattern space:
sed '/placeholder/{:l /ItemName/!{N;bl};/ItemName.*2/s/^/new1\nnew2\nnew3\n/}' file
Note that if `ItemName` is always two lines after `placeholder` then this simpler method also works:
sed '/placeholder/{N;N;/ItemName.*2/s/^/new1\nnew2\nnew3\n/}' file
There is also this complicated method of accumulating in the hold space rather than the pattern space:
sed '/placeholder/,/ItemName/{/placeholder/h;//!H;/ItemName/!d;//g;/ItemName.*2/s/^/new1\nnew2\nnew3\n/}' file
All methods produce this output:
[...]
[ placeholder ]
Categ #n
ItemName 1
[...]
new1
new2
new3
[ placeholder ]
Categ #n
ItemName 2
[...]
这是你提供的代码的翻译部分。
英文:
A loop probably makes sense to accumulate the block into the pattern space:
sed '/placeholder/{:l /ItemName/!{N;bl};/ItemName.*2/s/^/new1\nnew2\nnew3\n/}' file
Note that if ItemName
is always two lines after placeholder
then this simpler method also works:
sed '/placeholder/{N;N;/ItemName.*2/s/^/new1\nnew2\nnew3\n/}' file
There is also this complicated method of accumulating in the hold space rather than the pattern space:
sed '/placeholder/,/ItemName/{/placeholder/h;//!H;/ItemName/!d;//g;/ItemName.*2/s/^/new1\nnew2\nnew3\n/}' file
All methods produce this output:
[...]
[ placeholder ]
Categ #n
ItemName 1
[...]
new1
new2
new3
[ placeholder ]
Categ #n
ItemName 2
[...]
The simpler method is simply using N
to append more lines into the pattern space before it's printed.
The loop adds a label :l
and b
branches to that label until ItemName
.
The hold space method uses h
and H
to hold, d
to delete and not print, g
to get. As well as //
as shorthand to repeat same match.
I have been lazy with the matches and the lines inserted to make this all more readable. ItemName.*2
is especially lazy. Probably should be something like ItemName\s\+2\b
答案4
得分: 0
这可能适用于您(使用GNU sed和bash):
match='[ placeholder ]
Categ #n
ItemName 2'
insert='**new_line1**\n**new_line2**\n**new_line3**'
sed '1N;N;/^'"${match}"'$/!{P;D};i\'"${insert}"' file
打开一个三行窗口,直到找到匹配项,然后插入所需的字符串,之后两行窗口将继续,直到文件末尾。
英文:
This might work for you (GNU sed and bash):
match=''\[ placeholder \]\nCateg #n\nItemName 2'
insert='**new_line1**\n**new_line2**\n**new_line3**'
sed '1N;N;/^'"${match}"'$/!{P;D};i\'"${insert}" file
Open a three line window until a match occurs, then insert the required string and thereafter the two line window will continue until the end of file.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论