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

问题描述 投票:0回答:3

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

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

其中

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

这是我当前的 bash 脚本解决方案。它可以工作,但很难看。

(
  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

有人可以建议如何做这个清洁工吗?

  • 此 sed 脚本仅替换 LF,而不替换 CR。它将每一行累积到缓冲区中,然后执行

    s//g
    来替换其中的所有 LF。我想不出任何更干净的方法仍然可以在 Linux 和 OSX/BSD 上运行。

  • 我同时使用了 printf 和 echo。首先是 printf,因为我do想要在 Content-Length 标头之后发出 CRLFCRLF,并且您显然需要 printf 来实现这一点,因为带有转义的 echo 行为在各个平台上并不统一。接下来 echo 因为我希望 TXT 中的

    \r
    \n
    文字不转义,而 printf 会这样做。

上下文:有一个称为“语言服务器协议”的标准。基本上,你运行类似我在这里运行的

pyls
的东西,然后通过标准输入将 JsonRPC 传输到它,然后它通过管道返回内容。不同的人已经为 Python(我在这里使用的 pyls)、C#、C++、Typescript、PHP、OCaml、Go 和 Java 编写了语言服务器,每个人都倾向于用自己的语言编写语言服务器。自己的语言。

我想编写一个测试工具,它可以将一些示例 JsonRPC 数据包发送到任何此类服务器。

我认为最好用所有平台上开箱即用的通用基本 shell 脚本编写我的测试工具。这样每个人都可以针对他们的语言服务器使用我的测试工具。 (如果我用 Python 编写,对我来说会更容易编写,但它会迫使 C# 人员学习+安装 python 只是为了运行它,同样 Typescript、PHP、OCaml、Go 和其他语言各位。)

bash shell awk sed tr
3个回答
2
投票

有人可以建议如何做这个清洁工吗?

我猜最终也需要所有其他 JSON 转义

如果我已经可以使用 Python,我会非常非常努力地使用标准的 Python JSON 编码器,至少对于字符串转义部分。当你可以使用你已经熟悉了一半的已知可用的东西时,为什么还要把一些有用的东西拼凑在一起呢?

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

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

如果你懂一点 awk,他的解决方案几乎一目了然。我称之为“清洁工”。如果您不了解 awk,这似乎是一个熟悉 awk 的绝佳机会。


2
投票

我认为您的脚本的主要问题是没有将格式字符串与 printf 一起使用。使用 printf 的通常方法是在 格式字符串 中使用各种特殊字符(如

%s
%b
等)以及替换到格式字符串中的附加参数列表。

也就是说,当你说“[我使用] echo 因为我不想要 和 文字不转义, 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"

1
投票

a.py:

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

awk 脚本:

{
  gsub("\r", "\\r")
  gsub("\42", "\\\42")
  z = z $0 "\\n"
}
END {
  printf "Content-Length: %d\r\n", length(z) + 42
  printf "\r\n"
  printf "{\42jsonrpc\42: \0422.0\42, \42params\42: {\42text\42: \42%s\42}}", z
}

结果:

Content-Length: 81

{"jsonrpc": "2.0", "params": {"text": "print(\"alfa\")\r\nprint(\"bravo\")\r\n"}}
© www.soinside.com 2019 - 2024. All rights reserved.