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
请问有人可以建议如何做这个清洁剂吗?
此 sed 脚本仅替换 LF,不替换 CR。它将每一行累积到缓冲区中,然后执行 s//g
替换其中的所有 LF。我想不出在 Linux 和 OSX/BSD 上仍然有效的清洁剂。
我同时使用了 printf 和 echo。首先 printf 因为我 do 想在 Content-Length header 之后发出 CRLFCRLF,而你显然需要 printf因为带有转义符的 echo 行为在各个平台上并不统一。接下来 echo 因为我 不 希望 TXT 中的 \r
和 \n
文字不被转义,而 printf 会做。
上下文:有一个标准叫做 "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")
Awk 脚本:
{
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,我喜欢 解决方案。经验法则:
- 要处理文件集,请使用 shell
- 要处理文件中的数据,请使用 awk
- 如果 sed 不能简单地做到这一点,请参阅规则 #2
如果你懂一点awk,他的解法几乎一眼就能看懂。我会称之为“清洁工”。如果你不知道 awk,这似乎是一个很好的结识机会。
给定一个文件名,我想编写一个 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
请问有人可以建议如何做这个清洁剂吗?
此 sed 脚本仅替换 LF,不替换 CR。它将每一行累积到缓冲区中,然后执行
s//g
替换其中的所有 LF。我想不出在 Linux 和 OSX/BSD 上仍然有效的清洁剂。我同时使用了 printf 和 echo。首先 printf 因为我 do 想在 Content-Length header 之后发出 CRLFCRLF,而你显然需要 printf因为带有转义符的 echo 行为在各个平台上并不统一。接下来 echo 因为我 不 希望 TXT 中的
\r
和\n
文字不被转义,而 printf 会做。
上下文:有一个标准叫做 "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")
Awk 脚本:
{
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,我喜欢
- 要处理文件集,请使用 shell
- 要处理文件中的数据,请使用 awk
- 如果 sed 不能简单地做到这一点,请参阅规则 #2
如果你懂一点awk,他的解法几乎一眼就能看懂。我会称之为“清洁工”。如果你不知道 awk,这似乎是一个很好的结识机会。