Shell 脚本,转义换行但发出其他?

Shell script, escape newlines but emit others?

给定一个文件名,我想编写一个 shell-script 发出以下内容,并将其通过管道传输到一个进程中:

Content-Length:<LEN><CR><LF>
<CR><LF>
{ "jsonrpc":"2.0", "params":{ "text":"<ESCAPED-TEXT>" } }

其中 <ESCAPED-TEXT> 是文件的内容,但它的 CR、LF 和引号已被转义为 \r\n 以及 \"(我猜所有其他 JSON 转义最终也将需要),其中 <LEN> 是包含转义文本的最终 JSON 行的长度。

这是我当前的 bash-script 解决方案。它有效,但非常丑陋。

(
  TXT=`cat ~/a.py | sed -E -e :a -e '$!N; s/\n/\\n/g; ta' | sed 's/"/\\"/g'`
  CMD='{"jsonrpc":"2.0", "params":{ "text":{"'${TXT}'"}} }'
  printf "Content-Length: ${#CMD}\r\n\r\n"
  echo -n "${CMD}"
) | pyls

请问有人可以建议如何做这个清洁剂吗?

上下文:有一个标准叫做 "Language Server Protocol"。基本上你 运行 类似于 pyls 我在这里 运行,你通过 stdin 将 JsonRPC 传递给它,然后它通过管道返回内容。不同的人为 Python(我在这里使用的 pyls)、C#、C++、Typescript、PHP、OCaml、Go 和 Java 编写了语言服务器, 每个人都倾向于用自己的语言编写他们的语言服务器。

我想写一个 test-harness 可以将一些示例 JsonRPC 数据包发送到任何这样的服务器。

我想我的 test-harness 最好只使用所有平台上开箱即用的通用基本 shell-scripting 内容。这样每个人都可以在他们的语言服务器上使用我的 test-harness。 (如果我改为在 Python 上写它,那么我写起来会更容易,但它会迫使 C# 人员学习+安装 python 只是为了 运行 它,还有 Typescript、PHP、OCaml、Go 和其他人。)

a.py:

print("alfa")
print("bravo")

A​​wk 脚本:

{
  gsub("\r", "\r")
  gsub("", "\")
  z = z [=11=] "\n"
}
END {
  printf "Content-Length: %d\r\n", length(z) + 42
  printf "\r\n"
  printf "{jsonrpc: 22.0, params: {text: %s}}", z
}

结果:

Content-Length: 81

{"jsonrpc": "2.0", "params": {"text": "print(\"alfa\")\r\nprint(\"bravo\")\r\n"}}

我认为您的脚本的主要问题是没有使用带有 printf 的格式字符串。 printf 的通常使用方式是在 格式字符串 中使用各种特殊字符(如 %s%b 等)和一系列附加参数替换为格式字符串。

也就是说,当您说“[我使用] echo 是因为我不想对 \r 和 \n 文字进行转义,而 printf 会这样做”,问题只是没有使用 printf "%s" "$string".

无论如何,这里有一个关于如何使用这些东西在 bash 中完成一切而无需外部工具的想法:

escapes=('\n' '\r' '\"')         # the escapes we want to put into the output

txt=$(< ~/a.py);                 # read the file into a variable
for esc in "${escapes[@]}"; do
    # escapes are evaluated in a %b string w/ printf
    # using -v puts the result into a variable
    printf -v lit '%b' "$esc"
    # use built-in ${string//pattern/replacement} expansion
    txt=${txt//$lit/$esc}
done

txt='{"jsonrpc":"2.0", "params":{ "text":{"'$txt'"}} }'

# escapes in the format string are expanded
# but escapes in the argument substituted for %s are not
printf 'Content-Length: %s\r\n\r\n%s' "${#txt}"

"$txt"

Can anyone suggest how to do this cleaner, please?

I guess all other JSON escapes will eventually be needed as well

如果我已经可以使用 Python,我会非常非常努力地尝试使用标准 Python JSON encoder,至少对于字符串转义部分。当您可以使用您已经略微熟悉的已知有效的方法时,为什么还要将这种有效的方法拼凑在一起呢?

如果我没有 Python,我喜欢 解决方案。经验法则:

  1. 要处理文件集,请使用 shell
  2. 要处理文件中的数据,请使用 awk
  3. 如果 sed 不能简单地做到这一点,请参阅规则 #2

如果你懂一点awk,他的解法几乎一眼就能看懂。我会称之为“清洁工”。如果你不知道 awk,这似乎是一个很好的结识机会。