如何处理 bash 脚本中的转义用户事件描述以传递给 sed 命令?
How to handle escaping user event description in bash script to pass to a sed command?
我正在使用 curl 从 API 中获取事件描述,并将结果分配给 bash 中的变量,如下所示:
Event=$( curl -s -X GET https://api.vendor.com/v1/events/ev_$API_ID\
-H 'Accept: application/json' \
-u 'mykey:' )
EVTITLE=$(echo $Event | jq -r '.name')
DESC=$(echo $Event | jq -r '.description')
目前为止效果很好。但有时 EVTITLE 或 DESC 字符串在字符串中有 shell 个特殊字符,如 &、!有时引用。
所以,稍后,当我像这样将变量传递给 sed 命令时:
(替换模板文件中的值)
ti_sed="s/EVTITLE/"$EVTITLE"/"
sed -i -e "$ti_sed" filename
$EVTITLE 中的值类似于
Amy 为您和“其他事情”做问答!
我想避免 bash 在 sed 开始工作之前解释这些字符串。
有没有办法修饰字符串,使最终的 sed 输出看起来像输入?
例如,我可以在单引号之间获取 $EVTITLE 的字符串值吗?
Is there a way to groom the strings so the final sed output looks
like the input?
这是一个 bash
演示脚本,它从临时 JSON 中读取字符串
文件放入索引数组并让 GNU sed
编写自己的转换
用于编辑模板的脚本。
请注意\n
、\r
、\t
、\u
等在JSON源中将被转换
通过 jq -r
在 bash
和 sed
看到它们之前。 bash
脚本读取
换行符分隔的行和 不适用于包含 \n
.
的 JSON 字符串
下面有更多评论。
#!/bin/bash
jsonfile="$(mktemp)" templatefile="$(mktemp)"
# shellcheck disable=SC2064
trap "rm -f -- '${jsonfile}' '${templatefile}'" INT EXIT
cat << 'HERE' > "${jsonfile}"
{
"Name":"A1",
"Desc":"*A* \1 /does/ 'Q&A' for you\tand \"other things\" \@ $HOME !"
}
HERE
printf '%s\n' '---EVTITLE---' > "${templatefile}"
mapfile -t vars < <(
jq -r '.Name, .Desc' < "${jsonfile}"
)
wait "$!" || exit ## abort if jq failed
# shellcheck disable=SC2034
name="${vars[0]}" desc="${vars[1]}"
printf '%s\n' "${desc}" |
tee /dev/stderr |
sed -e 's/[\/&\n]/\&/g' -e 's/.*/s\/EVTITLE\/&\//' |
tee /dev/stderr |
sed -f /dev/stdin "${templatefile}"
这些是脚本输出的 3 行(标签扩展为
不同的长度)显示内容:
- shell变量
desc
- 生成的
sed
脚本
- 编辑后的模板文件
*A* /does/ 'Q&A' for you and "other things" \@ $HOME !
s/EVTITLE/*A* \1 \/does\/ 'Q\&A' for you and "other things" \@ $HOME !/
---*A* /does/ 'Q&A' for you and "other things" \@ $HOME !---
bash
存储它读取的字符串,不加修改地传递下去
使用 printf
到 sed
,这又会根据需要添加转义符
要在 s/EVTITLE/
和 /
之间插入的替换字符串,即
编辑模板文件所需的 sed
脚本。
在替换段中的一个sed
s
替换命令
根据以下内容具有特殊含义
POSIX
\
(反斜杠)转义字符本身
s
命令分隔符,默认为/
,但它可以是任何东西
除了反斜杠和换行符
&
(& 符号)引用整个匹配部分
\
(</code> 是数字 1 到 9 之一)引用匹配组 </li>
<li>文字换行符</li>
</ul>
<p>但有几个 <code>sed
将其他转义字符识别为替代字符。例如,
GNU sed
将像 C 中一样替换 \f
、\n
、\t
、\v
等,并且(除非
--posix
选项)其扩展 \L
、\l
、\U
、\u
和 \E
行为
在更换上。
(info sed -n 'The "s" Command'
、info sed -n Escapes
详细介绍了这一点
info sed --index-search POSIXLY_CORRECT
.)
这意味着所有反斜杠、命令分隔符、& 符号、
输入中的换行符必须转义,即前缀为
反斜杠,如果它们在用于
更换部分。这是通过询问 sed
到 s/[\/&\n]/\&/g
.
来完成的
回想一下正则表达式中使用的大多数元字符
(和 shell,就此而言),例如 ^$.*[]{}()
,没有特殊的
出现在 sed
的 s
的替换部分 中时的含义
命令等不应在那里转义。相反,&
不是
正则表达式元字符。
我正在使用 curl 从 API 中获取事件描述,并将结果分配给 bash 中的变量,如下所示:
Event=$( curl -s -X GET https://api.vendor.com/v1/events/ev_$API_ID\
-H 'Accept: application/json' \
-u 'mykey:' )
EVTITLE=$(echo $Event | jq -r '.name')
DESC=$(echo $Event | jq -r '.description')
目前为止效果很好。但有时 EVTITLE 或 DESC 字符串在字符串中有 shell 个特殊字符,如 &、!有时引用。
所以,稍后,当我像这样将变量传递给 sed 命令时: (替换模板文件中的值)
ti_sed="s/EVTITLE/"$EVTITLE"/"
sed -i -e "$ti_sed" filename
$EVTITLE 中的值类似于
Amy 为您和“其他事情”做问答!
我想避免 bash 在 sed 开始工作之前解释这些字符串。 有没有办法修饰字符串,使最终的 sed 输出看起来像输入? 例如,我可以在单引号之间获取 $EVTITLE 的字符串值吗?
Is there a way to groom the strings so the final sed output looks like the input?
这是一个 bash
演示脚本,它从临时 JSON 中读取字符串
文件放入索引数组并让 GNU sed
编写自己的转换
用于编辑模板的脚本。
请注意\n
、\r
、\t
、\u
等在JSON源中将被转换
通过 jq -r
在 bash
和 sed
看到它们之前。 bash
脚本读取
换行符分隔的行和 不适用于包含 \n
.
下面有更多评论。
#!/bin/bash
jsonfile="$(mktemp)" templatefile="$(mktemp)"
# shellcheck disable=SC2064
trap "rm -f -- '${jsonfile}' '${templatefile}'" INT EXIT
cat << 'HERE' > "${jsonfile}"
{
"Name":"A1",
"Desc":"*A* \1 /does/ 'Q&A' for you\tand \"other things\" \@ $HOME !"
}
HERE
printf '%s\n' '---EVTITLE---' > "${templatefile}"
mapfile -t vars < <(
jq -r '.Name, .Desc' < "${jsonfile}"
)
wait "$!" || exit ## abort if jq failed
# shellcheck disable=SC2034
name="${vars[0]}" desc="${vars[1]}"
printf '%s\n' "${desc}" |
tee /dev/stderr |
sed -e 's/[\/&\n]/\&/g' -e 's/.*/s\/EVTITLE\/&\//' |
tee /dev/stderr |
sed -f /dev/stdin "${templatefile}"
这些是脚本输出的 3 行(标签扩展为 不同的长度)显示内容:
- shell变量
desc
- 生成的
sed
脚本 - 编辑后的模板文件
*A* /does/ 'Q&A' for you and "other things" \@ $HOME !
s/EVTITLE/*A* \1 \/does\/ 'Q\&A' for you and "other things" \@ $HOME !/
---*A* /does/ 'Q&A' for you and "other things" \@ $HOME !---
bash
存储它读取的字符串,不加修改地传递下去
使用 printf
到 sed
,这又会根据需要添加转义符
要在 s/EVTITLE/
和 /
之间插入的替换字符串,即
编辑模板文件所需的 sed
脚本。
在替换段中的一个sed
s
替换命令
根据以下内容具有特殊含义
POSIX
\
(反斜杠)转义字符本身s
命令分隔符,默认为/
,但它可以是任何东西 除了反斜杠和换行符&
(& 符号)引用整个匹配部分\
(</code> 是数字 1 到 9 之一)引用匹配组 </li> <li>文字换行符</li> </ul> <p>但有几个 <code>sed
将其他转义字符识别为替代字符。例如, GNUsed
将像 C 中一样替换\f
、\n
、\t
、\v
等,并且(除非--posix
选项)其扩展\L
、\l
、\U
、\u
和\E
行为 在更换上。 (info sed -n 'The "s" Command'
、info sed -n Escapes
详细介绍了这一点info sed --index-search POSIXLY_CORRECT
.)这意味着所有反斜杠、命令分隔符、& 符号、 输入中的换行符必须转义,即前缀为 反斜杠,如果它们在用于 更换部分。这是通过询问
来完成的sed
到s/[\/&\n]/\&/g
.回想一下正则表达式中使用的大多数元字符 (和 shell,就此而言),例如
^$.*[]{}()
,没有特殊的 出现在sed
的s
的替换部分 中时的含义 命令等不应在那里转义。相反,&
不是 正则表达式元字符。