假设我有'abbc'字符串,我想替换:
如果我尝试两次替换,结果不是我想要的:
echo 'abbc' | sed 's/ab/bc/g;s/bc/ab/g'
abab
那么我可以使用什么sed命令替换如下?
echo abbc | sed SED_COMMAND
bcab
修改:
实际上文本可能有两个以上的模式,我不知道我需要多少替换。由于有一个答案说sed
是一个流编辑器,并且它的替换是贪婪的,我认为我需要使用一些脚本语言。
答案 0 :(得分:256)
也许是这样的:
sed 's/ab/~~/g; s/bc/ab/g; s/~~/bc/g'
将~
替换为您知道不会在字符串中的字符。
答案 1 :(得分:11)
我总是使用多个带有-e的语句
"""
A simple example of how to use the MongoDB reader and writer.
If you like, you can test it out with these commands (requires Docker and
virtualenv for python2):
$ virtualenv venv
$ source venv/bin/activate
$ pip install google-cloud-dataflow pymongo
$ # The following line is optional if mongod is running already
$ sudo service mongod stop
$ docker run -p 27017:27017 --name dataflowtest --rm mongo:3.2
$ docker exec -it dataflowtest mongo
> use mydb
> db.mycollection.insert({ _id: ObjectId() })
> exit
$ python -m simple
$ # The following line is optional if mongod was shut down previously
$ sudo service mongod start
"""
from __future__ import absolute_import
import logging
import apache_beam as beam
from apache_beam.options.pipeline_options import PipelineOptions
from beam_extended.io.mongodbio import ReadFromMongo, WriteToMongo
def transform_doc(document):
print(document)
return {'_id': str(document['_id'])}
def run(argv=None):
"""Main entry point; defines and runs the aggregation pipeline."""
connection_string = 'mongodb://localhost:27017'
# Can also fetch a connection string from a Google Cloud Storage file.
# This might be preferable to avoid pickling the mongodb connection string.
# E.g.
# connection_string = 'gs://my-bucket/mongo_connection_string.txt'
# where "mongo_connection_string.txt" contains a single line with the connection string.
# with beam.Pipeline(runner='DirectRunner', options=PipelineOptions()) as pipeline:
options = PipelineOptions()
with beam.Pipeline(options=options) as pipeline:
(pipeline
| 'read' >> ReadFromMongo(connection_string, 'mydb', 'mycollection', query={}, projection=['_id'])
| 'transform' >> beam.Map(transform_doc)
| 'save' >> WriteToMongo(connection_string, 'mydb', 'mycollection'))
# | 'save' >> beam.io.WriteToText('./simple.txt'))
if __name__ == '__main__':
# logging.getLogger().setLevel(logging.DEBUG)
logging.getLogger().setLevel(logging.INFO)
run()
这将在所有AND,GROUP BY,UNION和FROM之前附加一个'\ n',而'&'表示匹配的字符串,而'\ n&'表示要在匹配的字符串之前用'\ n'替换“匹配”
答案 2 :(得分:10)
以下是ooga's answer的变体,适用于多个搜索和替换对,而无需检查值的重复使用方式:
21
以下是一个例子:
之前:
sed -i '
s/\bAB\b/________BC________/g
s/\bBC\b/________CD________/g
s/________//g
' path_to_your_files/*.txt
后:
some text AB some more text "BC" and more text.
请注意,some text BC some more text "CD" and more text.
表示字边界,这是阻止\b
干扰搜索的原因(我在Ubuntu上使用GNU sed 4.2.2)。如果您没有使用单词边界搜索,则此技术可能无效。
另请注意,这与删除________
并将s/________//g
附加到命令末尾的结果相同,但不需要指定路径两次。
如果您知道文件as jthill suggested中没有显示空值,则可以使用&& sed -i 's/________//g' path_to_your_files/*.txt
或\x0
代替_\x0_
。
答案 3 :(得分:6)
sed
是一个流编辑器。它贪婪地搜索和替换。做你要求的唯一方法是使用中间替换模式并最终将其更改回来。
echo 'abcd' | sed -e 's/ab/xy/;s/cd/ab/;s/xy/cd/'
答案 4 :(得分:4)
这可能适合你(GNU sed):
sed -r '1{x;s/^/:abbc:bcab/;x};G;s/^/\n/;:a;/\n\n/{P;d};s/\n(ab|bc)(.*\n.*:(\1)([^:]*))/\4\n\2/;ta;s/\n(.)/\1\n/;ta' file
这使用查找表,该查找表在保留空间(HS)中准备并保存,然后附加到每一行。一个独特的标记(在这种情况下为\n
)被添加到行的开头,并用作在整个行的长度上沿着搜索进行碰撞的方法。一旦标记到达该行的末尾,该过程就完成并打印出查找表并丢弃标记。
N.B。查找表在最开始时准备好,并选择第二个唯一标记(在本例中为:
),以免与替换字符串冲突。
有一些评论:
sed -r '
# initialize hold with :abbc:bcab
1 {
x
s/^/:abbc:bcab/
x
}
G # append hold to patt (after a \n)
s/^/\n/ # prepend a \n
:a
/\n\n/ {
P # print patt up to first \n
d # delete patt & start next cycle
}
s/\n(ab|bc)(.*\n.*:(\1)([^:]*))/\4\n\2/
ta # goto a if sub occurred
s/\n(.)/\1\n/ # move one char past the first \n
ta # goto a if sub occurred
'
表格如下:
** ** replacement
:abbc:bcab
** ** pattern
答案 5 :(得分:2)
Tcl对此
有builtin$ tclsh
% string map {ab bc bc ab} abbc
bcab
这可以通过一次一个字符来处理字符串,从当前位置开始进行字符串比较。
在perl:
perl -E '
sub string_map {
my ($str, %map) = @_;
my $i = 0;
while ($i < length $str) {
KEYS:
for my $key (keys %map) {
if (substr($str, $i, length $key) eq $key) {
substr($str, $i, length $key) = $map{$key};
$i += length($map{$key}) - 1;
last KEYS;
}
}
$i++;
}
return $str;
}
say string_map("abbc", "ab"=>"bc", "bc"=>"ab");
'
bcab
答案 6 :(得分:1)
echo "C:\Users\San.Tan\My Folder\project1" | sed -e 's/C:\\/mnt\/c\//;s/\\/\//g'
替换
C:\Users\San.Tan\My Folder\project1
到
mnt/c/Users/San.Tan/My Folder/project1
以防有人需要将Windows路径的Windows路径替换为Linux(WSL)路径
答案 7 :(得分:0)
以下是基于oogas awk
sed
echo 'abbc' | awk '{gsub(/ab/,"xy");gsub(/bc/,"ab");gsub(/xy/,"bc")}1'
bcab
答案 8 :(得分:0)
对于出现单一模式,这可能是一种更简单的方法,您可以尝试如下操作: 回声“ abbc” | sed's / ab / bc /; s / bc / ab / 2'
我的输出:
~# echo 'abbc' | sed 's/ab/bc/;s/bc/ab/2'
bcab
对于多次出现的图案:
sed 's/\(ab\)\(bc\)/\2\1/g'
示例
~# cat try.txt
abbc abbc abbc
bcab abbc bcab
abbc abbc bcab
~# sed 's/\(ab\)\(bc\)/\2\1/g' try.txt
bcab bcab bcab
bcab bcab bcab
bcab bcab bcab
希望这会有所帮助!
答案 9 :(得分:0)
我相信这应该可以解决您的问题。我可能缺少一些极端情况,如果您注意到其中一个,请发表评论。
您需要一种从将来的模式中排除以前的替换的方法,这实际上意味着使输出可区分,并从搜索中排除这些输出,最后再次使输出变得不可区分。这与引用/转义过程非常相似,因此我将从中进行借鉴。
s/\\/\\\\/g
会转义所有现有的反斜杠s/ab/\\b\\c/g
用原始ab代替转义的bc s/bc/\\a\\b/g
用原始bc代替转义的ab s/\\\(.\)/\1/g
将所有转义的X替换为原始X 我没有考虑ab或bc中的反斜杠,但直觉上,我将以相同的方式跳过搜索并替换术语-\
现在匹配\\
,而替换为\\
显示为\
。
直到现在,我一直在使用反斜杠作为转义字符,但这不一定是最佳选择。几乎任何字符都可以使用,但是要谨慎选择需要在环境中转义,sed等的字符,具体取决于您打算如何使用结果。
答案 10 :(得分:0)
如果用变量替换字符串,则解决方案不起作用。 sed 命令需要用双引号代替单引号。
#sed -e "s/#replacevarServiceName#/$varServiceName/g" -e "s/#replacevarImageTag#/$varImageTag/g" deployment.yaml
答案 11 :(得分:0)
到目前为止发布的每个答案似乎都同意kuriouscoder在他的above post中所做的声明:
<块引用>做您要求的唯一方法是使用中间件 替换模式并最终将其改回
但是,如果您打算这样做,并且您的用法可能涉及的不仅仅是一些简单的字符串(也许您正在过滤数据等),那么与 sed
一起使用的最佳字符是换行符。这是因为由于 sed
是 100% 基于行的,换行符是您在获取新行时保证永远不会收到的唯一字符(忘记 GNU
多行扩展用于本次讨论)。
首先,这里有一个非常简单的方法来解决您的问题,使用换行符作为中间分隔符:
echo "abbc" | sed -E $'s/ab|bc/\\\n&/g; s/\\nab/bc/g; s/\\nbc/ab/g'
简单带来了一些权衡……如果您有多个变量,就像在您的原始帖子中一样,您必须将它们全部输入两次。性能也可能会有所提高。
使用 sed
做更多事情会变得非常讨厌。即使有一些更高级的功能,如分支控制和保持缓冲区(IMO 真的很弱),您的选择也非常有限。
只是为了好玩,我想出了一个替代方案,但我认为我没有任何特别的理由推荐它而不是本文前面的那个......你必须基本上制定自己的“约定” " 用于分隔符,如果您真的想在 sed
中做任何花哨的事情。这对于您的原始帖子来说太过分了,但它可能会为遇到此帖子并遇到更复杂情况的人激发一些想法。
我的约定如下:使用多个换行符来“保护”或“取消保护”您正在处理的行的一部分。换行符表示单词边界。两个换行符表示候选替换的替代。我不会立即替换,而是在下一行列出候选替换。三个换行符意味着一个值被“锁定”,就像你最初的帖子方式试图对 ab
和 bc
做的那样。在那之后,进一步的替换将被撤消,因为它们受到换行符的保护。如果我自己不这么说,那就有点复杂了……! sed
的真正意义不只是基础知识。
# Newlines
NL=$'\\\n'
NOT_NL=$'[\x01-\x09\x0B-\x7F]'
# Delimiters
PRE="${NL}${NL}&${NL}"
POST="${NL}${NL}"
# Un-doer (if a request was made to modify a locked-in value)
tidy="s/(\\n\\n\\n${NOT_NL}*)\\n\\n(${NOT_NL}*)\\n(${NOT_NL}*)\\n\\n/\\1\\2/g; "
# Locker-inner (three newlines means "do not touch")
tidy+="s/(\\n\\n)${NOT_NL}*\\n(${NOT_NL}*\\n\\n)/\\1${NL}\\2/g;"
# Finalizer (remove newlines)
final="s/\\n//g"
# Input/Commands
input="abbc"
cmd1="s/(ab)/${PRE}bc${POST}/g"
cmd2="s/(bc)/${PRE}ab${POST}/g"
# Execute
echo ${input} | sed -E "${cmd1}; ${tidy}; ${cmd2}; ${tidy}; ${final}"