在sed命令中使用多行变量

时间:2017-02-20 22:22:06

标签: bash sed

我有一个从STDOUT捕获的多线变量 我想使用这个多行变量将echo命令插入到另一个脚本(目标)中的第15行。

#!/bin/bash
TEST=`cat foo`

echo "$TEST"

sed -i "15i echo \"$TEST\" > someotherfile" target  

foo的内容:

apples
oranges
bananas
carrots

我认为sed命令在换行中读取,我确认我的foo有:

user@test$ cat foo | tr -cd '\n' | wc -c
4

当我运行test.sh脚本时,我会看到$TEST中的内容,但是sed命令出错:

user@test$ ./test.sh
apples
oranges
bananas
carrots
sed: -e expression #1, char 18: unknown command: `o'

我做错了什么? 提前谢谢。

4 个答案:

答案 0 :(得分:1)

尝试:

<强>解决方法1:

awk 'NR==15{print;system("cat foo");next} 1' Input_file

无需将完整的文件放入变量中,我们只需将其打印出来就可以打印出任何一行Input_file。

解决方案2:

line=15; sed -e "${line}r foo" target

或(在脚本模式下)

cat script.ksh
line=15;
sed -e "${line}r foo" target

您可以在哪里更改要从其他文件插入行的行数。

答案 1 :(得分:0)

i中的sed命令会插入以换行符结尾的文本行,直到不以反斜杠结尾的行。 ac命令类似。经典sed不喜欢第一行与i命令出现在同一行; GNU sed并不那么挑剔。

如果您手动编写命令,则需要编写:

15i\
echo "apples\
oranges\
bananas\
carrots" > someotherfile

现在问题是“如果文件foo包含名称列表,你想如何创建?”。有时,使用sed生成sed脚本非常有用。但是,如果您需要在符合i(或ac)命令的行的末尾处获得反斜杠,它也可以是复杂的,并且它更容易规避问题。

{
    echo "15i\\"
    sed -e '1s/^/echo "/' -e 's/$/\\/' -e '$s/\\$/" > someotherfile/' foo
} | sed -f /dev/stdin target

GNU sed可以使用-f -从标准输入读取其脚本; BSD(macOS)sed不喜欢这样,但您可以使用-f /dev/stdin代替(也适用于GNU sed),至少在有{{1}的系统上}。

答案 2 :(得分:0)

假设

GNU sed,正如问题中使用的语法所暗示的那样。

#!/bin/bash

# Read contents of file 'foo' into shell variable $test.
test=$(<foo)

# \-escape the newlines in $test for use in Sed.
testEscapedForSed=${test//$'\n'/\\$'\n'}

sed -i "15i echo \"$testEscapedForSed\" > someotherfile" target
  • 您的问题是多行字符串传递给sed函数,例如i(插入),需要在这些字符串中嵌入换行符被\ - 转义,以便sed知道字符串结束的位置以及其他命令(如果有的话)开始。

  • 另请注意:

答案 3 :(得分:0)

有趣的问题。 正如已经提到的那样,sed能够在另一个文件中插入多行文本的整个故事是,这个新的多行文本实际上必须有用于换行符的\n

因此我们可以使用sed将真正的新行字符转换为文字\n

$ a=$(tr '\n' '\\' <file3 |sed 's#[\]$##' |sed "s#[\]#\0n#g")
#Alternative: a=$(sed "s#[\]#\0n#g" <(sed 's#[\]$##' <(tr '\n' '\\' <file3)))
$ echo "$a"
apples\noranges\nbananas\ncarrots

此翻译的工作原理:
*首先,我们使用tr
用一个反斜杠替换所有新行 *然后我们从字符串的末尾删除反斜杠 *然后我们用backaslash和n char替换所有其他反斜杠。

由于现在变量$a在行之间包含文字\n,因此sed会将它们转换回实际的新行:

$ cat file4
Line1
line2
line3
$ sed "2i $a" file4
Line1
apples
oranges
bananas
carrots
line2
line3

结果:
可以使用两个命令替换Mutliline:

$ a=$(tr '\n' '\\' <file3 |sed 's#[\]$##' |sed "s#[\]#\0n#g")
$ sed "2i $a" file4

sed 2i表示在第2行之前插入文本。可以使用2a以便在第2行之后插入内容。

注:
根据似乎是重复的this post,将新行转换为文字\ n似乎可以通过以下方式完成:

a=$(echo ${a} | tr '\n' "\\n")

但是这种方法在我的系统中从未起作用。

备注2:
sed操作sed "2i $a" =在第2行之前插入变量$ a,也可以表示为sed "1 s/.*/\0\n$a/" =用相同的字符\0替换第一行的所有字符加上新行{{1加上变量\n =&gt;的内容在第1行之后插入$ a =在第2行之前插入$ a。