如何处理 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 -rbashsed 看到它们之前。 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 行(标签扩展为 不同的长度)显示内容:

  1. shell变量desc
  2. 生成的sed脚本
  3. 编辑后的模板文件
*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存储它读取的字符串,不加修改地传递下去 使用 printfsed,这又会根据需要添加转义符 要在 s/EVTITLE// 之间插入的替换字符串,即 编辑模板文件所需的 sed 脚本。

替换段中的一个seds替换命令 根据以下内容具有特殊含义 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.)

    这意味着所有反斜杠、命令分隔符、& 符号、 输入中的换行符必须转义,即前缀为 反斜杠,如果它们在用于 更换部分。这是通过询问 seds/[\/&\n]/\&/g.

    来完成的

    回想一下正则表达式中使用的大多数元字符 (和 shell,就此而言),例如 ^$.*[]{}(),没有特殊的 出现在 seds 的替换部分 中时的含义 命令等不应在那里转义。相反,& 不是 正则表达式元字符。