我正在尝试使用sed
和BASH变量进行查找和替换。由于替换内容包含许多/
个字符,因此我使用#
代替/
,这通常用于sed
:
sed -i "0,\#^$word#s##$replacement#" ./file
我要替换的项目包含\
符号:
replacement=$(echo "\macro{30\percent of bears eat fish.}")
然而,当我进行替换时,\
总是消失。
"\macro{30\percent of bears eat fish.}"
\t
,则会将其解释为缩进,但我只是希望它在输出中打印为\t
。如果在替换文字中找到sed
,\
或其他符号,如何使用/
进行查找和替换?
答案 0 :(得分:5)
当你拥有shell并且sed
都试图解释反斜杠时,生活总是变得棘手。事实上,它真的很痛苦。
让我们举个简单的例子:你希望sed
用一个符号替换一行上的第一个反斜杠:
sed 's/\\/@/' file
请注意,我们需要在这里指定两个反斜杠,因为命令是单引号,所以shell没有对我们做任何解释 - 谢天谢地!
现在,我们假设我们需要使用双引号而不是单引号。现在我们需要输入:
sed "s/\\\\/@/" file
为什么呢?因为shell首先扫描字符串,并且它看到反斜杠反斜杠并将其转换为单个反斜杠;然后它会看到第二个反斜杠反斜杠并将其转换为另一个反斜杠。所以,然后sed
可以看到两个反斜杠并完成你想要它做的事情。
您的计算机上可能有/bin/echo
(我在我的计算机上,Mac OS X 10.7.3),其行为与bash
的内置echo
不同。我可以得到以下输出(来自/bin/bash
):
$ echo '\\' | sed "s/\\\\/@/"
@\
$ /bin/echo '\\' | sed "s/\\\\/@/"
@\
$ echo '\\' | sed 's/\\\\/@/'
@
$ /bin/echo '\\' | sed 's/\\\\/@/'
@
$
让我们在工作中抛出另一个扳手(我的大脑受伤了 - 你的应对方式如何?)。我从/bin/sh
得到了一个不同的答案(与/bin/bash
非常相似但不完全相同;磁盘上的差异是64字节,两者都是bash
版本3.2):
$ echo '\\' | sed "s/\\\\/@/"
@
$ /bin/echo '\\' | sed "s/\\\\/@/"
@\
$ echo '\\' | sed 's/\\\\/@/'
\
$ /bin/echo '\\' | sed 's/\\\\/@/'
@
$
是的,有区别。现在我很困惑!
在您的讨论中,您提到使用:
replacement=$(echo "\\\macro{some text}")
这使生活变得复杂。你有shell处理该文本,而bash的内置echo
也处理文本。如果您使用bash
作为sh
,则会得到一个答案,如果您使用bash
作为bash
,则会得到另一个答案。
当我使用bash
作为sh
进行测试时,我发现:
replacement="\\\\macro{some text}" # 4 slashes, not 3
这会将两个反斜杠转换为$replacement
。您可以通过运行来证明:
$ /bin/echo "$replacement"
\\macro{some text}
$ echo "$replacement"
\macro{some text}
$
非常有用......所以,为了让$(echo ...)
在你后来echo
输出时在输出中产生两个反斜杠,你需要在字符串中不少于16个(!)反斜杠:< / p>
$ replacement=$(echo "\\\\\\\\\\\\\\\\macro{some text}")
$ echo "$replacement"
\\macro{some text}
$
小心:适用于bash-as-sh;运行bash-as-bash,你得到:
$ replacement=$(echo "\\\\\\\\\\\\\\\\macro{some text}")
$ echo "$replacement"
\\\\\\\\macro{some text
$
生活不是很有趣!因此,要使其工作,您将不得不对搜索模式和替换模式进行预处理,以便在每个模式中获得足够的反斜杠。多少?啊...
这是我打电话给的一个测试脚本,具有令人惊叹的原创性和明确的名称,xx
:
#!/bin/bash
echo "happy /word/ today" > file
word="/word/"
/bin/echo "word=<<$word>>"
replacement='\\\\macro{some text}'
/bin/echo "repl=<<$replacement>>"
echo "repl=<<$replacement>>"
/bin/echo sed -e "s#$word#$replacement#" file
sed -e "s#$word#$replacement#" file
echo
replacement="\\\\macro{some text}"
/bin/echo "repl=<<$replacement>>"
echo "repl=<<$replacement>>"
/bin/echo sed -e "s#$word#$replacement#" file
sed -e "s#$word#$replacement#" file
echo
replacement=$(echo "\\\\\\\\macro{some text}")
/bin/echo "$replacement"
echo "$replacement"
echo
replacement=$(echo "\\\\\\\\\\\\\\\\macro{some text}")
/bin/echo "$replacement"
echo "$replacement"
这是bash xx
的输出:
$ bash xx
word=<</word/>>
repl=<<\\\\macro{some text}>>
repl=<<\\\\macro{some text}>>
sed -e s#/word/#\\\\macro{some text}# file
happy \\macro{some text} today
repl=<<\\macro{some text}>>
repl=<<\\macro{some text}>>
sed -e s#/word/#\\macro{some text}# file
happy \macro{some text} today
\\\\macro{some text}
\\\\macro{some text}
\\\\\\\\macro{some text}
\\\\\\\\macro{some text}
$
这是sh xx
:
$ sh xx
word=<</word/>>
repl=<<\\\\macro{some text}>>
repl=<<\\macro{some text}>>
sed -e s#/word/#\\\\macro{some text}# file
happy \\macro{some text} today
repl=<<\\macro{some text}>>
repl=<<\macro{some text}>>
sed -e s#/word/#\\macro{some text}# file
happy \macro{some text} today
\\macro{some text}
\macro{some text}
\\\\macro{some text}
\\macro{some text}
$
在所有(大部分)问题的答案中。要说我很惊讶地发现bash-as-bash和bash-as-sh之间的这种差异并没有开始覆盖领土。
答案 1 :(得分:4)
您的问题可能不是反斜杠。或者至少,你的一个问题。 : - )
在我系统上安装的sed中,您可以使用#
作为替换的分隔符(即s#pattern#replacement#
),但不能作为初始搜索的一部分。因此,你必须使用类似的东西:
sed -i "1,/^$word/s##$replacement#" ./file
查看我的结果:
[ghoti@pc ~]$ printf 'one\ntwo\nthree\nfour\nfive\n' | sed '1,/three/d'
four
five
[ghoti@pc ~]$ printf 'one\ntwo\nthree\nfour\nfive\n' | sed '1,#three#d'
sed: 1: "1,#three#d": expected context address
[ghoti@pc ~]$
我在FreeBSD,但我很确定GNU sed的工作方式是一样的。
但是,如果您尝试匹配的模式中存在不兼容的字符,则无法帮助您。您只需要确保$word
是一个格式正确的正则表达式,可以在sed
中使用。
至于反斜杠...如果上面的建议给你带来任何快乐,请尝试将替换模式中的任何反斜杠加倍。但是,一次只处理一个问题,并从更简单的$replacement
开始,以确保您的基本sed符号正常运行。
<强>更新强>
另外,为了它的乐趣:
[ghoti@pc ~]$ word="word"
[ghoti@pc ~]$ replacement="\\\macro{some text};"
[ghoti@pc ~]$ printf "Replace a word with some text.\n" | sed "s#$word#$replacement#"
Replace a \macro{some text}; with some text.
[ghoti@pc ~]$ replacement="\\\\macro{some text};"
[ghoti@pc ~]$ printf "Replace a word with some text.\n" | sed "s#$word#$replacement#"
Replace a \macro{some text}; with some text.
[ghoti@pc ~]$ printf "Replace a word with some text.\n" | sed "s/$word/$replacement/"
Replace a \macro{some text}; with some text.
[ghoti@pc ~]$ word="two"
[ghoti@pc ~]$ printf "one\ntwo\nthree\n" | sed "s/^$word/$replacement/"
one
\macro{some text};
three
[ghoti@pc ~]$
答案 2 :(得分:2)
这可能对您有用:
sed -i "0,\#^$word#s##$(printf '%q' $replacement)#" ./file
答案 3 :(得分:2)
word=$(echo -E "wo\rd")
replacement=$(echo -E "r/e\p")
echo -ne "a\nb\nc\nd\nwo\\\\rd\ne\nf\n" | sed -e "0,\#^${word//\\/\\\\}# s##${replacement//\\/\\\\}#"
请注意,您仍会遇到其他角色问题,&amp;和#替换字符串,当然还有单词字符串中的所有有效正则表达式字符
以下处理正则表达式字符
word=$(echo -E "^\$.*[#]wo\rd" | sed 's:[]\[\^\$\.\*#\\]:\\&:g')
replacement=$(echo -E "&#r/e\p" | sed 's:[&#\\]:\\&:g')
echo -ne "a\nb\nc\nd\n^\$.*[#]wo\\\\rd\ne\nf\n" | sed -e "0,\#^${word}# s##${replacement}#"
答案 4 :(得分:1)
试试这个(如果我理解你的问题):
R="macro{some text}"
sed -i "0,\#^$word#s##\\$R#" ./file
答案 5 :(得分:1)
试试这个
输入
/home/Scripts/dummyrun
Unix命令
$> sed -i "s%/home/Scripts/dummyrun%Newpath%g" Input
<强>输出强>
打开输入文件,更改将自动反映。
$> cat Input
Newpath
上面的命令将/ home / Scripts / dummyrun替换为输入文件中的Newpath。