为什么我不能将 npm install 通过管道传输到 sed,同时保留颜色和进度更新?
Why can't I pipe npm install to sed, while preserving color and progress updates?
如果我键入 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(duh...),所以我需要使用 npm i 2>&1 | sed 's/^/ /
,但这会从输出中删除颜色并且我看不到进度条,您可以在下面的 gif 中看到。
Edit2:颜色已通过 npm i --color=always | sed 's/^/ /
修复,但我仍然看不到进度条。此外,它似乎在所有输出之后的行中添加了行......我假设这是由输出颜色代码引起的?您可以在下面的 gif 中看到这种现象:
目前状态:
您在这里遇到了几个问题,其中大部分与 npm
处理其输出的方式有关。
捕获警告
首先请注意,npm
输出 warnings 并在 stderr
上更新 progress,而只有最终结果至 stdout
。因此,为了处理警告,您必须将 stderr
重定向到 stdout
,例如:
npm install 2>&1 | sed 's/^/ /'
保留颜色
但是现在 stderr
通过管道传输到 sed
进程,您会注意到 npm
省略了着色!然而,这是大多数命令行工具(如 ls
、grep
等)的标准行为。只有当输出到 TTY
设备(即到用户,而不是文件或管道)时,它们才会输出 ANSI 转义(颜色)序列。确定文件描述符是否连接到 TTY
的常用方法是通过 isatty(int fd)
function. It turns out (after some digging) npm
使用相同的机制。
要解决着色问题,我们有两个选择:
(1) 我们可以 强制 颜色输出 --color=always
选项(类似于 ls
, grep
, 其他):
npm install --color=always 2>&1 | sed 's/^/ /'
或者,(2) 我们可以使用一个名为 script
的工具,它将 伪造 一个 TTY
任何 program/script 运行:
的输出设备
script -feqc 'npm install' /dev/null | sed 's/^/ /'
请注意,我们不必再将 stderr
重定向到 stdout
,script
会为我们做这件事。此外,script
会将完整的输出保存到我们选择的文件中(在这种情况下我们不需要它,所以我们说 /dev/null
)。 (顺便说一句,-f
将在每次写入后刷新输出,-e
将确保命令的退出代码返回到 parent/shell,-q
强制 quiet 模式,没有信息消息,使用 -c cmd
我们将命令提供给 运行。)
保留进度更新
好的,现在我们缩进了警告并保留了颜色,但是我们丢失了进度(栏)更新!
为什么会这样?好吧,因为 npm
在一行中输出了完整的进度。在每次进度更新时,它将移动到字符位置零(同一行!)并打印新进度。对于sed
,完整的进度只是一行,由于sed
是面向行的,所以会等到行尾(\n
) 在任何处理(和输出)之前。
显然,我们需要降低一个级别 - 逐个字符地处理。为了达到缩进的效果,我们将每次出现的 \n
替换为 \n<4 spaces>
.
通常,对于字符翻译我们可以使用tr
,但在这里我们需要更多,因为在某些情况下(\n
)我们需要将一个字符扩展为多个。一种方法是使用这个简单的 bash
script/function:
#!/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
-to-\n<spaces>
替换器稍微复杂一些。我们还必须处理 returns (\r
) ,它被 npm
大量用于进度更新和依赖树绘制,并确保每个新行都从位置零开始(因此 \r
旁边每个 \n
).
如果我键入 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(duh...),所以我需要使用 npm i 2>&1 | sed 's/^/ /
,但这会从输出中删除颜色并且我看不到进度条,您可以在下面的 gif 中看到。
Edit2:颜色已通过 npm i --color=always | sed 's/^/ /
修复,但我仍然看不到进度条。此外,它似乎在所有输出之后的行中添加了行......我假设这是由输出颜色代码引起的?您可以在下面的 gif 中看到这种现象:
目前状态:
您在这里遇到了几个问题,其中大部分与 npm
处理其输出的方式有关。
捕获警告
首先请注意,npm
输出 warnings 并在 stderr
上更新 progress,而只有最终结果至 stdout
。因此,为了处理警告,您必须将 stderr
重定向到 stdout
,例如:
npm install 2>&1 | sed 's/^/ /'
保留颜色
但是现在 stderr
通过管道传输到 sed
进程,您会注意到 npm
省略了着色!然而,这是大多数命令行工具(如 ls
、grep
等)的标准行为。只有当输出到 TTY
设备(即到用户,而不是文件或管道)时,它们才会输出 ANSI 转义(颜色)序列。确定文件描述符是否连接到 TTY
的常用方法是通过 isatty(int fd)
function. It turns out (after some digging) npm
使用相同的机制。
要解决着色问题,我们有两个选择:
(1) 我们可以 强制 颜色输出 --color=always
选项(类似于 ls
, grep
, 其他):
npm install --color=always 2>&1 | sed 's/^/ /'
或者,(2) 我们可以使用一个名为 script
的工具,它将 伪造 一个 TTY
任何 program/script 运行:
script -feqc 'npm install' /dev/null | sed 's/^/ /'
请注意,我们不必再将 stderr
重定向到 stdout
,script
会为我们做这件事。此外,script
会将完整的输出保存到我们选择的文件中(在这种情况下我们不需要它,所以我们说 /dev/null
)。 (顺便说一句,-f
将在每次写入后刷新输出,-e
将确保命令的退出代码返回到 parent/shell,-q
强制 quiet 模式,没有信息消息,使用 -c cmd
我们将命令提供给 运行。)
保留进度更新
好的,现在我们缩进了警告并保留了颜色,但是我们丢失了进度(栏)更新!
为什么会这样?好吧,因为 npm
在一行中输出了完整的进度。在每次进度更新时,它将移动到字符位置零(同一行!)并打印新进度。对于sed
,完整的进度只是一行,由于sed
是面向行的,所以会等到行尾(\n
) 在任何处理(和输出)之前。
显然,我们需要降低一个级别 - 逐个字符地处理。为了达到缩进的效果,我们将每次出现的 \n
替换为 \n<4 spaces>
.
通常,对于字符翻译我们可以使用tr
,但在这里我们需要更多,因为在某些情况下(\n
)我们需要将一个字符扩展为多个。一种方法是使用这个简单的 bash
script/function:
#!/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
-to-\n<spaces>
替换器稍微复杂一些。我们还必须处理 returns (\r
) ,它被 npm
大量用于进度更新和依赖树绘制,并确保每个新行都从位置零开始(因此 \r
旁边每个 \n
).