Shell,查找包含的行,并仅替换它之后的行
Shell, find line containing, and replace on only line after it
我有一个文件位于:/Applications/Firefox.app/Contents/info.plist
。我试图找到包含 LSUIElement
的行,然后用 <string>firefox</string>
.
替换整行
这是我得到的,到目前为止,它什么也没做:
line=“LSUIElement”
rep="<string>firefox</string>"
sed -e "s/${line}/${rep}/g" /Applications/Firefox.app/Contents/info.plist > /Applications/Firefox.app/Contents/info.plist.profilist
mv /Applications/Firefox.app/Contents/info.plist.profilist /Applications/Firefox.app/Contents/info.plist
使用 awk,你可以这样做:
awk '/LSUIElement/{i=NR+1}{if(NR==i){gsub(/1/,"0",[=10=])}}1' File > tmp && mv tmp File
逻辑:
如果找到 LSUIElement
,将变量 i
设置为 NR+1
(即下一行/记录编号)。作为第二部分,如果 NR
(当前 record/line)是 i
(之前保存的),则将 1
替换为 0
。因此,替换只会发生在带有模式 LSUIElement
.
的行之后的行中
让我们为那些手边没有这样的 plist 文件的人简化问题。
echo -e "foo bar baz\nthe suspicious LSUIElement in line 2\nand some more garbage" > luis.txt
cat luis.txt
foo bar baz
the suspicious LSUIElement in line 2
and some more garbage
line=“LSUIElement”
rep="<string>firefox</string>"
所以这里我们有问题 1:sed 表达式中的斜杠通常像 's/a/b/g' 中那样分隔各部分。
sed -e "s/${line}/${rep}/g" luis.txt > luis2.txt
mv luis2.txt luis.txt
我们首先去寻找低垂的果实。 Sed,至少是 Gnu-sed,有一个选项 -i 来改变文件。在后台,可能有一个
正在制作副本,因为文件经常会缩小或增大,所以很难避免,但我们不需要重定向和 mv:
sed -i "s/${line}/${rep}/g" luis.txt
您甚至可以让 sed 生成备份文件。 AFAIK sed 在正常情况下不需要 -e ,但在这种情况下 gnu-sed 可能是特殊的。测试或阅读手册页。
现在是困难的部分。我们在没有 -i 的情况下进行测试以避免破坏。第一次测试,第一次惊喜:
line=“LSUIElement”
rep="<string>firefox</string>"
echo $line
# “LSUIElement”
echo $rep
# <string>firefox</string>
为什么 line 显示引号,而 rep 不显示?啊,这些是印刷引语?这有什么重要的吗?那你应该提一下,因为它很容易监督。我决定在没有他们的情况下离开,直到需要为止。
如果我们将 sed 表达式中的 / 替换为 |,我们可以避免与 $rep 变量中的 sed 语法冲突:
sed "s|${line}|${rep}|g" luis.txt
foo bar baz
the suspicious <string>firefox</string> in line 2
and some more garbage
这里我们完全替换了图案,而不是线条。
sed "s|.*${line}.*|${rep}|g" luis.txt
foo bar baz
<string>firefox</string>
and some more garbage
这是在替换整行。
sed "s|${line}.*|${rep}|g" luis.txt
foo bar baz
the suspicious <string>firefox</string>
and some more garbage
这是从包含模式到 EOL 的替换。
如果我们想在下一行中替换一些东西 - 那么替换什么?例如,垃圾?
我们可以在不替换 $line 的情况下匹配它,而是调用一系列简短的 2 命令,'n' for 'read next line' 并在那里执行我们的 s-substitution。这些命令必须包装到 {} 中。因为我们不需要将 / 更改为 |在前一部分,我们切换回那里:
sed "/${line}.*/{n;s|garbage|$rep|}" luis.txt
foo bar baz
the suspicious LSUIElement in line 2
and some more <string>firefox</string>
命令:
sed -i.bak "/${line}.*/{n;s|garbage|$rep|}" luis.txt
会创建这样的备份文件luis.txt.bak
有了一个模式,正如现在在评论中注意到的那样,它看起来像:
sed -i.bak "/${line}.*/{n;s|<string>.*</string>|$rep|}" luis.txt
确定它必须有多具体(1,数字,无关紧要)。
我有一个文件位于:/Applications/Firefox.app/Contents/info.plist
。我试图找到包含 LSUIElement
的行,然后用 <string>firefox</string>
.
这是我得到的,到目前为止,它什么也没做:
line=“LSUIElement”
rep="<string>firefox</string>"
sed -e "s/${line}/${rep}/g" /Applications/Firefox.app/Contents/info.plist > /Applications/Firefox.app/Contents/info.plist.profilist
mv /Applications/Firefox.app/Contents/info.plist.profilist /Applications/Firefox.app/Contents/info.plist
使用 awk,你可以这样做:
awk '/LSUIElement/{i=NR+1}{if(NR==i){gsub(/1/,"0",[=10=])}}1' File > tmp && mv tmp File
逻辑:
如果找到 LSUIElement
,将变量 i
设置为 NR+1
(即下一行/记录编号)。作为第二部分,如果 NR
(当前 record/line)是 i
(之前保存的),则将 1
替换为 0
。因此,替换只会发生在带有模式 LSUIElement
.
让我们为那些手边没有这样的 plist 文件的人简化问题。
echo -e "foo bar baz\nthe suspicious LSUIElement in line 2\nand some more garbage" > luis.txt
cat luis.txt
foo bar baz
the suspicious LSUIElement in line 2
and some more garbage
line=“LSUIElement”
rep="<string>firefox</string>"
所以这里我们有问题 1:sed 表达式中的斜杠通常像 's/a/b/g' 中那样分隔各部分。
sed -e "s/${line}/${rep}/g" luis.txt > luis2.txt
mv luis2.txt luis.txt
我们首先去寻找低垂的果实。 Sed,至少是 Gnu-sed,有一个选项 -i 来改变文件。在后台,可能有一个 正在制作副本,因为文件经常会缩小或增大,所以很难避免,但我们不需要重定向和 mv:
sed -i "s/${line}/${rep}/g" luis.txt
您甚至可以让 sed 生成备份文件。 AFAIK sed 在正常情况下不需要 -e ,但在这种情况下 gnu-sed 可能是特殊的。测试或阅读手册页。
现在是困难的部分。我们在没有 -i 的情况下进行测试以避免破坏。第一次测试,第一次惊喜:
line=“LSUIElement”
rep="<string>firefox</string>"
echo $line
# “LSUIElement”
echo $rep
# <string>firefox</string>
为什么 line 显示引号,而 rep 不显示?啊,这些是印刷引语?这有什么重要的吗?那你应该提一下,因为它很容易监督。我决定在没有他们的情况下离开,直到需要为止。
如果我们将 sed 表达式中的 / 替换为 |,我们可以避免与 $rep 变量中的 sed 语法冲突:
sed "s|${line}|${rep}|g" luis.txt
foo bar baz
the suspicious <string>firefox</string> in line 2
and some more garbage
这里我们完全替换了图案,而不是线条。
sed "s|.*${line}.*|${rep}|g" luis.txt
foo bar baz
<string>firefox</string>
and some more garbage
这是在替换整行。
sed "s|${line}.*|${rep}|g" luis.txt
foo bar baz
the suspicious <string>firefox</string>
and some more garbage
这是从包含模式到 EOL 的替换。
如果我们想在下一行中替换一些东西 - 那么替换什么?例如,垃圾?
我们可以在不替换 $line 的情况下匹配它,而是调用一系列简短的 2 命令,'n' for 'read next line' 并在那里执行我们的 s-substitution。这些命令必须包装到 {} 中。因为我们不需要将 / 更改为 |在前一部分,我们切换回那里:
sed "/${line}.*/{n;s|garbage|$rep|}" luis.txt
foo bar baz
the suspicious LSUIElement in line 2
and some more <string>firefox</string>
命令:
sed -i.bak "/${line}.*/{n;s|garbage|$rep|}" luis.txt
会创建这样的备份文件luis.txt.bak
有了一个模式,正如现在在评论中注意到的那样,它看起来像:
sed -i.bak "/${line}.*/{n;s|<string>.*</string>|$rep|}" luis.txt
确定它必须有多具体(1,数字,无关紧要)。