简体   繁体   English

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

[英]Shell script, escape newlines but emit others?

Given a filename, I want to write a shell-script which emits the following, and pipes it into a process: 给定一个文件名,我想编写一个shell脚本,它发出以下内容,并将其传递给一个进程:

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

where <ESCAPED-TEXT> is the content of the file but its CRs, LFs and quotation marks have been escaped as \\r and \\n and \\" (and I guess all other JSON escapes will eventually be needed as well), and where <LEN> is the length of final JSON line that includes the escaped text. 其中<ESCAPED-TEXT>是文件的内容,但其CR,LF和引号已被转义为\\r\\n\\" (我猜最终也需要所有其他JSON转义),以及<LEN>是包含转义文本的最终JSON行的长度。

Here's my current bash-script solution. 这是我目前的bash脚本解决方案。 It works but is ugly as heck. 它有效,但很难看。

(
  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

Can anyone suggest how to do this cleaner, please? 有谁能建议怎么做这个更清洁,好吗?

  • This sed script only replaces LFs, not CRs. 这个sed脚本只替换LF,而不是CR。 It accumulates each line into the buffer and then does a s//g to replace all LFs in it. 它将每一行累积到缓冲区中,然后执行s//g以替换其中的所有LF。 I couldn't figure out anything cleaner that still worked on both Linux and OSX/BSD. 我无法弄清楚在Linux和OSX / BSD上仍然有效的清洁工具。

  • I used both printf and echo. 我使用了printf和echo。 First printf because I do want to emit the CRLFCRLF after the Content-Length header, and you apparently need printf for that because the behavior of echo with escapes isn't uniform across platforms. 第一个printf,因为我确实想发出Content-Length头后CRLFCRLF,你显然需要printf进行,由于回声与逃逸行为是不统一的跨平台。 Next echo because I don't want the \\r and \\n literals inside TXT to be unescaped, which printf would do. 下一个回声,因为我希望TXT中的\\r\\n文字未被转义,printf会做什么。

Context: there's a standard called "Language Server Protocol". 上下文:有一个称为“语言服务器协议”的标准。 Basically you run something like the pyls I'm running here, and you pipe in JsonRPC to it over stdin, and it pipes back stuff. 基本上你运行类似的pyls我在这里运行,而且您在JsonRPC管过来标准输入,它的管道回来的东西。 Different people have written language servers for Python (the pyls I'm using here), and C#, and C++, and Typescript, and PHP, and OCaml, and Go, and Java, and each person tends to write their language server in their own language. 不同的人为Python(我在这里使用的pyls),C#,C ++,Typescript,PHP,OCaml,Go和Java编写了语言服务器,每个人都倾向于在他们的语言服务器中编写语言服务器。自己的语言。

I want to write a test-harness which can send some example JsonRPC packets into any such server. 我想编写一个测试工具,可以将一些示例JsonRPC数据包发送到任何此类服务器。

I figured it'd be better to write my test-harness in just the common basic shell-scripting stuff that's available on all platforms out of the box. 我认为最好将我的测试工具编写在开箱即用的所有平台上常见的基本shell脚本编写工具中。 That way everyone can use my test-harness against their language server. 这样每个人都可以使用我的测试工具来对抗他们的语言服务器。 (If I wrote it on Python instead, say, it'd be easier for me to write, but it would force the C# folks to learn+install python just to run it, and likewise the Typescript, PHP, OCaml, Go and other folks.) (如果我在Python上写它,比如说,它对我来说更容易编写,但它会迫使C#人学习+安装python只是为了运行它,同样也是Typescript,PHP,OCaml,Go等乡亲。)

a.py: a.py:

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

Awk script: 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
}

Result: 结果:

Content-Length: 81

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

I think the main problem with your script is not using format strings with printf. 我认为你的脚本的主要问题是没有使用printf的格式字符串。 The usual way that printf is used is with various special characters in the format string (like %s , %b , etc) and a list of additional arguments that are substituted into the format string. printf的常用方法是使用格式字符串中的各种特殊字符(如%s%b等)以及替换为格式字符串的其他参数列表。

That is, when you say "[I used] echo because I don't want the \\r and \\n literals to be unescaped, which printf would do", the problem is just not using printf "%s" "$string" . 也就是说,当你说“[我用过]回声,因为我不希望\\ r和\\ n文字未被转义,哪个printf会做”,问题就是不使用printf "%s" "$string"

Anyway, here's an idea of how to use this stuff to get everything done in bash with no external tools: 无论如何,这里有一个想法,即如何使用这些东西在没有外部工具的情况下完成所有操作:

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" “$ TXT”

Can anyone suggest how to do this cleaner, please? 有谁能建议怎么做这个更清洁,好吗?

I guess all other JSON escapes will eventually be needed as well 我想最终也需要所有其他JSON转义

If I already had Python at my disposal, I'd try really, really hard to use the standard Python JSON encoder , at least for the string escaping part. 如果我已经拥有了Python,我会尝试使用标准的Python JSON编码器 ,至少对于字符串转义部分。 Why hack together something that kind of works when you can use something known to work that you already are halfway familiar with? 当你可以使用已经熟悉的已知工作的东西时,为什么要将某些东西组合在一起呢?

If I didn't have Python, I like Steve Penny's solution. 如果我没有Python,我喜欢Steve Penny的解决方案。 Rules of thumb: 经验法则:

  1. to process sets of files, use the shell 要处理文件集,请使用shell
  2. to process data in a file, use awk 要处理文件中的数据,请使用awk
  3. if sed can't do it trivially, see rule #2 如果sed不能做到这一点,请参阅规则#2

If you know a little awk, his solution is easy to understand almost at a glance. 如果你知道一点点awk,他的解决方案几乎可以一目了然。 I would call that "cleaner". 我会称之为“清洁”。 If you don't know awk, this would seem to be an excellent opportunity to become acquainted. 如果你不懂awk,这似乎是一个很好的机会。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM