首先和我在一起,谢谢。假设我有
$ echo $'foo\nbar'
foo
bar
现在,当我将字符串分配给Bash变量时,Bash不再提供相同的垂直输出:
$ str='foo\nbar'
$
$ echo $str
foo\nbar
$
$ echo $'str'
str
尝试printf:
$ printf "$str\n"
foo
bar
这些示例出于说明目的,因为我正在寻找一种在$ str变量内扩展换行符的方法,以便可以在sed替换(插入)端替换$ str变量。
# this does not work:
sed -i.bak $'/<!-- insert here -->/i\\\n'$'str'$'\\\n' index.html
# this works as expected though:
sed -i.bak $'/<!-- insert here -->/i\\\n'foo$'\\\n'bar$'\\\n' index.html
我做了几种方法来破解它,但是都没有用;这是一个示例:
# this does not work:
sed -i.bak $'/<!-- insert here -->/i\\\n'`printf 'foo\\x0Abar'`$'\\\n' index.html
进一步的测试中,我意识到只要变量不包含换行符,事情就会按预期进行:
# This works as long as str2 does not contain any newline.
str2='foo_bar'
sed -i.bak $'/<!-- insert here -->/i\\\n'$str2$'\\\n' index.html
预期结果是sed将在index.html文件的<!-在此插入->之前插入2个衬里。
foo
bar
<!-- insert here -->
我尝试通过一种班轮来实现这一目标。我知道我可以将sed分解为垂直的多行形式,这对我来说会更容易;但是,我想探讨一下是否有一种内衬样式。
这可行吗?
我的系统是macOS High Sierra 10.13.6
Bash版本:3.2.57(1)-发行版
BSD sed的最新更新时间为2005年5月10日
答案 0 :(得分:0)
echo -e $str
-e是
答案 1 :(得分:0)
使用sed
命令r
插入任意文本
str="abc\ndef"
tmp=$(mktemp)
(
echo
printf -- "$str"
echo
) > "$tmp"
sed -i.bak '/<!-- insert here -->/r '"$tmp" index.html
rm -r "$tmp"
sed
将换行符解释为命令分隔符。 ;
并不是sed
的命令分隔符,只有换行符。不要在;
命令中添加/后缀}
或w
或空格-它会被解释为文件名的一部分(是的,也包含空格)。 sed
之类的w
或r
命令由换行符转义。
如果您想获得更大的灵活性,请转到awk
。
答案 2 :(得分:0)
您的示例有一些细微的错误,因此这里有一些有关bash和sed中字符串中的引号和换行符的示例。
报价一般如何工作:
# bash converts escape-sequence '\n' to real newline (0x0a) before passing it to echo
$ echo $'foo\nbar'
foo
bar
# bash passes literal 8 characters 'foo\nbar' to echo and echo simply prints them
$ echo 'foo\nbar'
foo\nbar
# bash passes literal 8 characters 'foo\nbar' to echo and echo converts escape-sequence
$ echo -e 'foo\nbar'
foo
bar
# bash passes literal string 'foo\nbar' to echo (twice)
# then echo recombines both arguments using a single space
$ str='foo\nbar'
$ echo $str "$str"
foo\nbar foo\nbar
# bash interprets escape-sequences and stores result 'foo<0x0a>bar' in str,
# then passes two arguments 'foo' and 'bar' to echo, due to "word splitting"
# then echo recombines both arguments using a single space
$ str=$'foo\nbar'
$ echo $str
foo bar
# bash interprets escape-sequences and stores result 'foo<0x0a>bar' in str,
# then passes it as a single argument to echo, without "word splitting"
$ str=$'foo\nbar'
$ echo "$str"
foo
bar
在处理sed中的换行符时如何应用外壳引号
# replace a character with newline, using newline's escape-sequence
# sed will convert '\n' to a literal newline (0x0a)
$ sed 's/-/foo\nbar/' <<< 'blah-blah'
# replace a character with newline, using newline's escape-sequence in a variable
# sed will convert '\n' to a literal newline (0x0a)
$ str='foo\nbar' # str contains the escape-sequence '\n' and not a literal newline
$ sed 's/-/'"$str"'/' <<< 'blah-blah'
# replace a character with newline, using a literal newline.
# note the line-continuation-mark \ after 'foo' before the literal newline,
# which is part of the sed script, since everything in-between '' is literal
$ sed 's/-/foo\
bar/' <<< 'blah-blah' # end-of-command
# replace a character with newline, using a newline in shell-escape-mode
# note the same line-continuation-mark \ before $'\n', which is part of the sed script
# note: the sed script is a single string composed of three parts '…\', $'\n' and '…',
$ sed 's/-/foo\'$'\n''bar/' <<< 'blah-blah'
# the same as above, but with a single shell-escape-mode string instead of 3 parts.
# note the required quoting of the line-continuation-mark with an additional \ escape
# i.e. after shell-escaping the sed script contains a single \ and a literal newline
$ sed $'s/-/foo\\\nbar/' <<< 'blah-blah'
# replace a character with newline, using a shell-escaped string in a variable
$ str=$'\n' # str contains a literal newline (0x0a) due to shell escaping
$ sed 's/-/foo\'"$str"'bar/' <<< 'blah-blah'
# same as above with the required (quoted) line-continuation inside the variable
# note, how the single \ from '…foo\' (previous example) became \\ inside $'\\…'
$ str=$'\\\n' # str contains \ and a literal newline (0x0a) due to shell escaping
$ sed 's/-/foo'"$str"'bar/' <<< 'blah-blah'
所有sed示例将打印相同:
blahfoo
barblah
因此,sed替换字符串中的换行符必须为
(1)换行符的转义序列(即'\n'
),因此sed可以用文字换行符替换它,或者
(2)文字换行符,其后有换行符(即$'\\\n'
或'\'$'\n'
,与'\\\n'
或'\\n'
或{{1}不同})。
这意味着您需要用换行符的转义序列$'\\n'
替换每个文字换行符<0x0a>
或在其前面插入 line-continuation-mark 双引号扩展之前,替换字符串中的每个文字换行符将其替换为sed的替换替换字符串。
由于有关sed中转义的更多注意事项,我建议您使用\n
的{{1}}函数,而不是通过awk
将替换字符串作为变量传递,例如
gsub
PS:我不知道这个答案是否对您完全正确,因为您的操作系统使用了过时的bash版本。