编写脚本来自动化一些事情。在运行 sed 命令将 curl 的输出插入到文件中的行号时遇到了问题
我尝试了该命令的多种变体,但 sed 只给出了错误。
sed "49i/.*/\"$(curl URL)\"/" file.php
sed: -e expression #1, char 105: extra characters after command
任何想法都值得赞赏,谢谢
答案1
curl URL
($()
删除后)的输出尾随换行符(newline(s))可能包含换行符。它会被插入到应该是 脚本的命令行参数中sed
。该工具会解析代码,遇到换行符后49i
,会将后面的内容解释为脚本中的下一个命令。
您收到错误。情况可能会更糟:输出curl
可能会将语法有效的sed
代码注入脚本。您不希望出现这种情况。
即使你使用$(curl URL | tr -d '\n')
删除全部换行符,的输出curl
可能仍然不会逐字插入(例如反斜杠将具有特殊含义)。
解决方案:让其curl
写入一个临时文件,然后让其sed
打印该文件。该文件的内容不会被解释为代码。
看起来您希望 的输出curl
出现在第 49 行的原始内容之前。如果是这样,您需要r
在第 48 行使用(因为r
计划文本以供稍后输出)。
您的代码尝试在表单中插入某些内容/.*/"curl output here"/
。如果这不是尝试使用s
with语法所产生的结果i
,那么您也应该将这些附加片段写入文件。
通常情况下,您可以curl
使用 写入文件curl -o
。在这种情况下,它可能不是您想要的,因为它不会删除尾随换行符(而$()
您使用 会删除尾随换行符)。因此或许这:
tmpfile="$(mktemp)"
printf '/.*/"%s"/' "$(curl URL)" >"$tmpfile"
sed "48 r $tmpfile" file.php
rm "$tmpfile"
注意,如果输出curl
太长,通常会失败。更强大的解决方案是curl
直接打印到文件,然后删除末尾的换行符在下一步中。
临时文件的路径不得包含换行符。如果路径包含换行符,则路径的某些部分将被解释为 sed 命令,可能无效;这是一个与您遇到的错误有些类似的错误。路径不会包含换行符,除非您的路径$TMPDIR
包含换行符(但实际上不应该包含换行符)。如果出现问题(例如mktemp
不可用),请使用另一种方法选择临时位置。在最基本的设置中,位置可能是硬编码的(但您不应该同时运行多个脚本实例)。
答案2
sed
的i...\n
命令与 的语法不同s/.../.../...
,我认为这是这里的主要问题。此外,您的curl
输出可能包含换行符,这最终会终止i
命令。
s/find/replace/
将搜索find
并交换replace
在下面的例子中,与正则表达式匹配的文本3
被换出。
$ echo -e "1\n2\n3\n4\n5" | sed 's/3/new line/'
1
2
new line
4
5
inew line
new line
将在匹配的行之前插入
在下面的例子中,我们没有给出地址或匹配项,因此每一个输入行已new line
插入在其之前。
$ echo -e "1\n2\n3\n4\n5" | sed 'inew line'
new line
1
new line
2
new line
3
new line
4
new line
5
您想要做的似乎是在给定的行号处插入新行(又名“地址"),可以像这样实现。请注意,该i
命令以换行符(或字符串结尾)终止 -new line
插入在前面,它不会替换第三行。
$ echo -e "1\n2\n3\n4\n5" | sed '3inew line'
1
2
new line
3
4
5
现在,当您使用 的输出时curl
,您可能会发现其中包含一个换行符,这将终止命令i
……因此您需要将curl
的输出转换为单行,或者仅包含第一行 - 您可以使用head
或等工具xxd
来帮助:
$ curl "${url}"
line one
line two
line three
仅保留第一行:
$ new_line="$(curl -s "${url}" | head -n 1)"
$ echo -e "1\n2\n3\n4\n5" | sed '3i'"${new_line}"
1
2
line one
3
4
5
将所有换行符(\r\n
和\n
)转义为文字字符\n
。sed
然后将它们转换回换行符:
$ new_line="$(curl -s "${url}" | xxd -p | sed -re 's/(0d)?0a/5c6e/g;s/5c6e$//' | xxd -r -p)"
$ echo -e "1\n2\n3\n4\n5" | sed '3i'"${new_line}"
1
2
line one
line two
line three
3
4
5
将所有换行符(\r\n
和\n
)转义为文字字符\\n
。sed
然后会将它们转换为文字字符\n
,从而插入一行:
$ new_line="$(curl -s "${url}" | xxd -p | sed -re 's/(0d)?0a/5c5c6e/g;s/5c5c6e$//' | xxd -r -p)"
$ echo -e "1\n2\n3\n4\n5" | sed '3i'"${new_line}"
1
2
line one\nline two\nline three
3
4
5
这表明有可能但是,更好的方法可能是使用 和 重建文件head
,curl
就像tail
这样……将来它可能会更具可读性:
$ echo -e "1\n2\n3\n4\n5" > "${file}"
$ tmpfile="$(mktemp)"
$ ( head -n 2 < "${file}"; curl "${url}"; tail -n +3 < "${file}" ) > "${tmpfile}"
$ mv "${tmpfile}" "${file}"
$ cat "${file}"
1
2
line one
line two
line three
3
4
5