我怎样才能更换氮使用命令在文件中第 th(例如,第三次)出现字符串(或模式) sed
?我的意思是氮文件中的第 次出现,而不是氮一行中的第 次出现 或 行中的第一次出现 氮第 条匹配线。一行中可能会多次出现,并且一次出现(匹配)可能是部分单词。
例子:
仅更改文件中第三次出现的is
to 。us
我的输入文件包含:
hai this is linux.
hai this is unix.
hai this is mac.
hai this is unchanged.
预期输出是:
hai this is linux.
hai thus is unix.
hai this is mac.
hai this is unchanged.
请注意,“this”已替换为“th”我们”在第二行。
答案1
用 来完成就容易多了perl
。
要更改第三次出现的位置:
perl -pe 's{is}{++$n == 3 ? "us" : $&}ge'
每出现 3次就更改一次:
perl -pe 's{is}{++$n % 3 ? $& : "us"}ge'
答案2
sed
如果以前的换行符被替换为任何其他字符,则可以使用它,例如:
tr '\n' '\000' | sed 's/is/us/3' | tr '\000' '\n'
与纯(GNU)相同sed
:
sed ':a;N;$!ba;s/\n/\x0/g;s/is/us/3;s/\x0/\n/g'
(sed
换行替换无耻地从https://stackoverflow.com/a/1252191/4488514)
答案3
当替换字符串每行仅出现一次时,您可以组合不同的实用程序。
当输入位于文件“input”中并且您将“is”替换为“us”时,您可以使用
LINENR=$(cat input | grep -n " is " | head -3 | tail -1 | cut -d: -f1)
cat input | sed ${LINENR}' s/ is / us /'
答案4
p='[:punct:]' s='[:space:]'
sed -Ee'1!{/\n/!b' -e\} \
-e's/(\n*)(.*)/ \2 \1/' \
-e"s/is[$p]?[$s]/\n&/g" \
-e"s/([^$s])\n/\1/g;1G" \
-e:c -e"s/\ni(.* )\n{3}/u\1/" \
-e"/\n$/!s/\n//g;/\ni/G" \
-e's//i/;//tc' \
-e's/^ (.*) /\1/;P;$d;N;D'
该位sed
仅包含is
从一行到下一行的出现次数。它应该可靠地处理每行尽可能多的is
es,并且不需要缓冲旧行 - 它只是为is
遇到的每个不属于另一个单词的部分保留一个换行符。
结果是它只会修改文件中的第三次出现 - 并且每行都会包含计数。因此,如果文件如下所示:
1. is is isis
2. is does
...它将打印...
1. is is isis
2. us does
它首先通过在每行的头部和尾部插入一个空格来处理边缘情况。这使得单词边界更容易确定。
接下来,它通过在紧邻零个或一个标点符号字符(后跟一个空格)的所有出现的 es 之前插入一个 ewline来查找有效的is
es 。它执行另一遍操作并删除紧随其后的非空格字符的所有换行符。留下的标记将匹配and但不匹配or 。\n
is
\n
is.
is
this
?is
接下来,它将每个标记收集到字符串的尾部 - 对于\ni
行上的每个匹配,它都会将\n
ewline 附加到字符串的尾部,并将其替换为i
或u
。如果\n
连续有 3 个ewlines 聚集在字符串的尾部,那么它使用 u - 否则使用 i。第一次使用 au 也是最后一次 - 替换引发了无限循环,归结为get line, print line, get line, print line,
依此类推。
在每个 try 循环周期结束时,它会清除插入的空格,仅打印到模式空间中第一个出现的换行符,然后再次执行。
l
我将在循环的开头添加一个ook 命令,例如:
l; s/\ni(.* )\n{9}/u\1/...
...看看它在处理此输入时会做什么:
hai this is linux.
hai this is unix.
hai this is mac.
hai this is unchanged is.
...所以这就是它的作用:
hai this \nis linux. \n$ #behind the scenes
hai this is linux. #actually printed
hai this \nis unix. \n\n$ #it builds the marker string
hai this is unix.
\n\n\n$ #only for lines matching the
\n\n\n$ #pattern - and not otherwise.
hai this \nis mac. \n\n\n$ #here's the match - 3 ises so far in file.
hai this us mac. #printed
hai this is unchanged is. #no look here - this line is never evaled
is
每行有更多 es 可能更有意义:
nthword()( p='[:punct:]' s='[:space:]'
sed -e '1!{/\n/!b' -e\} \
-e 's/\(\n*\)\(.*\)/ \2 \1/' \
-e "s/$1[$p]\{0,1\}[$s]/\n&/g" \
-e "s/\([^$s]\)\n/\1/g;1G;:c" \
-e "${dbg+l;}s/\n$1\(.* \)\n\{$3\}/$2\1/" \
-e '/\n$/!s/\n//g;/\n'"$1/G" \
-e "s//$1/;//tc" -e 's/^ \(.*\) /\1/' \
-e 'P;$d;N;D'
)
这实际上是相同的事情,但是是用 POSIX BRE 和基本参数处理编写的。
printf 'is is. is? this is%.0s\n' {1..4} | nthword is us 12
...得到...
is is. is? this is
is is. is? this is
is is. is? this us
is is. is? this is
...如果我启用${dbg}
:
printf 'is is. is? this is%.0s\n' {1..4} |
dbg=1 nthword is us 12
...我们可以看着它迭代...
\nis \nis. \nis? this \nis \n$
is \nis. \nis? this \nis \n\n$
is is. \nis? this \nis \n\n\n$
is is. is? this \nis \n\n\n\n$
is is. is? this is
\nis \nis. \nis? this \nis \n\n\n\n\n$
is \nis. \nis? this \nis \n\n\n\n\n\n$
is is. \nis? this \nis \n\n\n\n\n\n\n$
is is. is? this \nis \n\n\n\n\n\n\n\n$
is is. is? this is
\nis \nis. \nis? this \nis \n\n\n\n\n\n\n\n\n$
is \nis. \nis? this \nis \n\n\n\n\n\n\n\n\n\n$
is is. \nis? this \nis \n\n\n\n\n\n\n\n\n\n\n$
is is. is? this \nis \n\n\n\n\n\n\n\n\n\n\n\n$
is is. is? this us
is is. is? this is