我有一个从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'
我做错了什么? 提前谢谢。
答案 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
命令会插入以换行符结尾的文本行,直到不以反斜杠结尾的行。 a
和c
命令类似。经典sed
不喜欢第一行与i
命令出现在同一行; GNU sed
并不那么挑剔。
如果您手动编写命令,则需要编写:
15i\
echo "apples\
oranges\
bananas\
carrots" > someotherfile
现在问题是“如果文件foo
包含名称列表,你想如何创建?”。有时,使用sed
生成sed
脚本非常有用。但是,如果您需要在符合i
(或a
或c
)命令的行的末尾处获得反斜杠,它也可以是复杂的,并且它更容易规避问题。
{
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
知道字符串结束的位置以及其他命令(如果有的话)开始。
$test
中的所有换行符,其前缀为\
,使用ANSI C-quoted string $'\n'
生成实际的换行符另请注意:
我已将TEST
重命名为test
,因为all-uppercase shell-variable names should be avoided。
我使用了现代命令替换语法$(..)
来代替旧语法`...`
。
$(<foo)
稍微提高效率 - 虽然是非标准的 - 一次读取文件内容的方式。
答案 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。