这个问题在这里已经有了答案:Using different delimiters in sed commands and range address (2 answers) Closed 9 months ago。
我有一个本地开发的 Visual Studio 项目。代码文件必须部署到远程服务器。唯一的问题是它们包含的 URL,它们是硬编码的。
该项目包含诸如 ?page=one
之类的 URL。要使链接在服务器上有效,它必须是 /page/one
。
我决定在部署之前用 sed 替换我的代码文件中的所有 URL,但我被困在斜杠上。
我知道这不是一个很好的解决方案,但它很简单,可以为我节省很多时间。我必须替换的字符串总数少于 10 个。必须检查的文件总数约为 30。
描述我的情况的示例如下:
我正在使用的命令:
sed -f replace.txt < a.txt > b.txt
replace.txt
包含所有字符串:
s/?page=one&/pageone/g
s/?page=two&/pagetwo/g
s/?page=three&/pagethree/g
a.txt
:
?page=one&
?page=two&
?page=three&
运行 sed 命令后 b.txt
的内容:
pageone
pagetwo
pagethree
我希望 b.txt
包含的内容:
/page/one
/page/two
/page/three
最简单的方法是在搜索/替换行中使用不同的分隔符,例如:
s:?page=one&:pageone:g
您可以使用不属于任一字符串的任何字符作为分隔符。或者,您可以使用反斜杠对其进行转义:
s/\//foo/
这会将 /
替换为 foo
。如果您不知道替换字符串中可能出现哪些字符(例如,如果它们是 shell 变量),您可能希望使用转义的反斜杠。
s
命令可以使用任何字符作为分隔符;使用 s
之后的任何字符。我从小就使用#
。像这样:
s#?page=one&#/page/one#g
关于 sed 的一个非常有用但鲜为人知的事实是,熟悉的 s/foo/bar/
命令可以使用任何标点符号,而不仅仅是斜杠。一个常见的替代方法是 s@foo@bar@
,从中可以看出如何解决您的问题。
在特殊字符前添加 \:
s/\?page=one&/page\/one\//g
等等
s/foo\/bar/foo_bar/
会起作用,但 /foo\/bar/foo_bar/
不会。
在我正在开发的系统中,要被 sed 替换的字符串是来自用户的输入文本,该文本存储在变量中并传递给 sed。
如本文前面所述,如果 sed 命令块中包含的字符串包含 sed 使用的实际分隔符,则 sed 会因语法错误而终止。考虑以下示例:
这有效:
$ VALUE=12345
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345
这打破了:
$ VALUE=12345/6
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
sed: -e expression #1, char 21: unknown option to `s'
在我的情况下,替换默认分隔符不是一个可靠的解决方案,因为我不想限制用户输入 sed 使用的特定字符作为分隔符(例如“/”)。
但是,转义输入字符串中出现的任何分隔符都可以解决问题。考虑以下在 sed 解析输入字符串之前系统地转义输入字符串中的分隔符的解决方案。这种转义可以使用 sed 本身作为替换来实现,即使输入字符串包含分隔符,这种替换也是安全的 - 这是因为输入字符串不是 sed 命令块的一部分:
$ VALUE=$(echo ${VALUE} | sed -e "s#/#\\\/#g")
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345/6
我已将其转换为供各种脚本使用的函数:
escapeForwardSlashes() {
# Validate parameters
if [ -z "$1" ]
then
echo -e "Error - no parameter specified!"
return 1
fi
# Perform replacement
echo ${1} | sed -e "s#/#\\\/#g"
return 0
}
VALUE="01\\\/01\\\/2018"
此行应该适用于您的 3 个示例:
sed -r 's#\?(page)=([^&]*)&#/\1/\2#g' a.txt
我使用 -r 来保存一些 escaping 。
该行对于您的一,二,三情况应该是通用的。你不必做 3 次
使用您的示例(a.txt)进行测试:
kent$ echo "?page=one&
?page=two&
?page=three&"|sed -r 's#\?(page)=([^&]*)&#/\1/\2#g'
/page/one
/page/two
/page/three
replace.txt
应该是
s/?page=/\/page\//g
s/&//g
匿名者的好回答。 \ 解决了我尝试转义 HTML 字符串中的引号时的问题。
因此,如果您使用 sed 返回一些 HTML 模板(在服务器上),请使用双反斜杠而不是单反斜杠:
var htmlTemplate = "<div style=\\"color:green;\\"></div>";
sed
是 stream editor,因为您可以使用 |
(管道)通过 sed
发送 标准流(特别是 STDIN 和 STDOUT)并以编程方式即时更改它们,使它是 Unix 哲学传统中的一个方便的工具;但也可以使用下面提到的 -i
参数直接编辑文件。
考虑以下事项:
sed -i -e 's/few/asd/g' hello.txt
s/
用于s将找到的表达式 few
替换为 asd
:
少数,勇敢。 asd,勇敢的人。
/g
代表“全局”,意思是对整行执行此操作。如果您省略 /g
(使用 s/few/asd/
,无论如何总是需要三个斜杠)并且 few
在同一行出现两次,则只有第一个 few
更改为 asd
:
少数男人,少数女人,勇敢的。 asd 男人,少数女人,勇敢的人。
这在某些情况下很有用,例如更改行首的特殊字符(例如,将某些人用来在电子邮件线程中引用先前材料的大于符号替换为水平制表符,同时在行的后面留下引用的代数不等式untouched),但在您指定 anywhere few
出现的示例中,它应该被替换,请确保您拥有该 /g
。
以下两个选项(标志)合二为一,-ie
:
-i
选项用于编辑文件 hello.txt
上的 in 位置。
-e
选项表示要运行的 expression/命令,在本例中为 s/
。
注意:使用 -i -e
进行搜索/替换很重要。如果您执行 -ie
,您将为每个附加了字母“e”的文件创建一个备份。
不定期副业成功案例分享
sed
时,将正则表达式命令放在双引号中是标准操作过程。我没有在回答中使用它们,因为我没有显示整个sed
命令行,而只是像 OP 所做的那样显示了sed
正则表达式命令字符串。如果你把它放在一个文件中,就像 OP 所做的那样,你不需要引号。