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

时间:2017-02-06 17:53:45

标签: bash shell awk sed tr

给定一个文件名,我想编写一个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-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

有人可以建议怎么做这个清洁工吗?

  • 此sed脚本仅替换LF,而不是CR。它将每一行累积到缓冲区中,然后执行s//g以替换其中的所有LF。我无法找到任何在Linux和OSX / BSD上都有效的清洁工具。

  • 我同时使用了printf和echo。首先 printf ,因为我想要在Content-Length标题之后发出CRLFCRLF,并且你显然需要printf,因为带有转义的echo的行为不是&t跨平台统一。接下来回显因为我希望TXT内的\r\n文字未被转义,而printf会这样做。

上下文:有一个名为&#34;语言服务器协议&#34;的标准。基本上你运行像pyls我在这里运行的东西,然后你通过stdin管道JsonRPC到它,它管道回来的东西。不同的人为Python编写语言服务器(我在这里使用的pyls),C#,C ++,Typescript,PHP,OCaml,Go和Java,每个人都倾向于编写他们的语言服务器用他们自己的语言。

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

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

3 个答案:

答案 0 :(得分: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"}}

答案 1 :(得分:1)

我认为你的脚本的主要问题是没有使用printf的格式字符串。 printf的常用方法是使用格式字符串中的各种特殊字符(如%s%b等)以及替换为其他参数的列表。格式字符串。

也就是说,当你说“[我用过]回声,因为我不希望\ r \ n和\ 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”

答案 2 :(得分:1)

  

有人可以建议怎么做这个清洁工吗?

     

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

如果我已经掌握了Python,我会尝试使用标准Python JSON encoder,至少对于字符串转义部分非常困难。当你可以使用已经熟悉的已知工作的东西时,为什么要将某些东西组合在一起呢?

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

  1. 处理文件集,使用shell
  2. 处理文件中的数据,请使用awk
  3. 如果sed不能做到这一点,请参阅规则#2
  4. 如果你知道一点点问题,他的解决方案几乎可以一目了然。我会称之为#34;更清洁&#34;。如果你不了解awk,这似乎是一个熟悉的绝佳机会。