如果我输入 npm i | sed "s/^/ /"
,输出npm i
打印到标准输出时没有间隔。例如。我得到以下信息:
$ npm i | sed "s/^/ /"
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.0.0
(node_modules/chokidar/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for
fsevents@1.1.2: wanted {"os":"darwin","arch":"any"} (current:
{"os":"linux","arch":"x64"})
npm WARN [name_removed]@0.0.2 No repository field.
npm WARN [name_removed]@0.0.2 No license field.
而不是:
$ npm i | sed "s/^/ /"
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.0.0
(node_modules/chokidar/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for
fsevents@1.1.2: wanted {"os":"darwin","arch":"any"} (current:
{"os":"linux","arch":"x64"})
npm WARN [name_removed]@0.0.2 No repository field.
npm WARN [name_removed]@0.0.2 No license field.
编辑:
警告将发送到 stderr(呃...),所以我需要使用 npm i 2>&1 | sed 's/^/ /
,但这会从输出中删除颜色,并且我看不到进度条,您可以在下面的 gif 中看到。
编辑2:颜色通过 npm i --color=always | sed 's/^/ /
固定,但我仍然看不到进度条。此外,它似乎在所有输出后面的行中添加了行...我认为这是由输出的颜色代码引起的?您可以在下面的 gif 中看到这种现象:
最佳答案
您在这里遇到了几个问题,其中大多数与 npm
的方式有关。处理其输出。
捕获警告
首先请注意 npm
stderr
上输出警告并更新进度 ,而只有最终结果会转到 stdout
。因此,为了处理警告,您必须重定向 stderr
至stdout
像这样的东西:
npm install 2>&1 | sed 's/^/ /'
保留颜色
但现在有了 stderr
通过管道发送到sed
过程中,你会注意到npm
省略着色!然而,这是大多数命令行工具的标准行为(例如 ls
、 grep
等)。仅当输出到 TTY
时,它们才会输出 ANSI 转义(颜色)序列。设备(即用户,而不是文件或管道)。确定文件描述符是否连接到 TTY
的常用方法通过 isatty(int fd)
功能。事实证明 ( after some digging ) npm
使用相同的机制。
要解决着色问题,我们有两种选择:
(1) 我们可以使用 --color=always
强制颜色输出选项(类似于 ls
、 grep
等):
npm install --color=always 2>&1 | sed 's/^/ /'
或者,(2)我们可以使用名为 script
的工具这将伪造 TTY
任何程序/脚本运行的输出设备:
script -feqc 'npm install' /dev/null | sed 's/^/ /'
请注意,我们不必重定向 stderr
至stdout
不再了,script
为我们做到这一点。另外,script
会将完整的输出保存到我们选择的文件中(在本例中我们不需要它,所以我们说 /dev/null
)。 (顺便说一句,-f
将在每次写入后刷新输出,-e
将确保命令的退出代码返回到父级/shell,-q
强制安静模式,没有信息消息,并且使用 -c cmd
我们提供要运行的命令。)
保留进度更新
好的,现在我们已经缩进了警告并保留了颜色,但是我们丢失了进度(栏)更新!
为什么会发生这种情况?嗯,因为npm
在一行中输出完整的进度。每次进度更新时,它将移动到字符位置零(同一行!)并打印新进度。对于 sed
,完整的进度只是一行,并且从sed
开始是面向行的,它会等到行尾( \n
)再进行任何处理(和输出)。
显然,我们需要降低一级 - 逐个字符地进行处理。为了达到缩进的效果,我们将替换每个出现的 \n
与 \n<4 spaces>
.
通常,对于字符翻译,我们可以使用 tr
,但这里我们需要的不止这些,因为在某些情况下( \n
)我们需要将一个字符扩展到多个字符。一种方法是使用这个简单的 bash
脚本/函数:
#!/bin/bash
# read each character of stdin, indenting each line
interactive_indent() {
local space=' '
echo -n "$space"
while IFS= read -r -d '' -n1 chr; do
[[ $chr == $'\n' ]] && chr="\\n\\r$space"
[[ $chr == $'\r' ]] && chr="\\r$space"
echo -ne "$chr"
done
echo -ne '\r'
}
例如:
$ echo -e 'one\ntwo\rthree' | interactive_indent
one
three
最后,我们找到了交互式 npm
的解决方案流程:
script -feqc 'npm install' /dev/null | interactive_indent
这将传递每个字符(显示进度),同时缩进每行(在 \n
或 \r
之后)。
请注意我们的interactive_indent
函数比简单的 \n
稍微复杂一些-到- \n<spaces>
替代者。我们还必须处理 \r
大量使用的回车符 ( npm
)对于进度更新和依赖关系树绘制,并确保每个新行从位置零开始(因此 \r
与每个 \n
旁边)。
关于node.js - 为什么我不能通过管道 npm install 到 sed,同时保留颜色和进度更新?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46493608/