Node.js 为什么我不能将npm安装到sed,同时保留颜色和进度更新?

Node.js 为什么我不能将npm安装到sed,同时保留颜色和进度更新?,node.js,bash,sed,npm,npm-install,Node.js,Bash,Sed,Npm,Npm Install,如果我键入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: Unsupp

如果我键入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的/^/,但这会从输出中删除颜色,并且我看不到进度条,您可以在下面的gif中看到

Edit2:Color是通过npm i-Color=always | sed的/^//固定的,但是我仍然看不到进度条。此外,它似乎在所有输出之后的行中添加行…我假设这是由输出的颜色代码引起的?您可以在下面的gif中看到这种现象:

当前状态:

您在这里遇到了几个问题,其中大多数与npm处理其输出的方式有关

捕捉警告 首先请注意,npm会输出警告并更新stderr上的进度,而只有最终结果才会进入stdout。因此,为了处理警告,您必须使用以下命令将stderr重定向到stdout:

npm install 2>&1 | sed 's/^/    /'
保色 但现在将stderr管道连接到sed进程,您会注意到npm忽略了着色!然而,这是大多数命令行工具(如ls、grep等)的标准行为。。只有当输出到TTY设备(即用户,而不是文件或管道)时,它们才会输出ANSI转义颜色序列。确定文件描述符是否连接到TTY的常用方法是通过函数。事实证明,npm使用的是相同的机制

要解决着色问题,我们有两个选项:

1我们可以使用与ls、grep和其他类似的选项强制颜色输出:

npm install --color=always 2>&1 | sed 's/^/    /'
或者,2我们可以使用一个名为的工具,为任何程序/脚本运行伪造TTY输出设备:

script -feqc 'npm install' /dev/null | sed 's/^/    /'
请注意,我们不再需要将stderr重定向到stdout,脚本会为我们这样做。另外,脚本将把完整的输出保存到我们选择的文件中。在本例中,我们不需要它,所以我们使用/dev/null。顺便说一句,-f将在每次写入后刷新输出,-e将确保命令的退出代码返回到parent/shell,-q强制安静模式,没有信息消息,并且使用-c cmd我们提供要运行的命令

保存进度更新 好的,现在我们已经缩进警告并保留颜色,但是我们已经丢失了进度条更新

为什么会这样?因为npm在一行中输出完整的进度。在每次进度更新时,它将移动到同一行的字符位置零!并打印新的进度。对于sed,完整的进度仅为一行,并且由于sed是面向行的,因此在任何处理和输出之前,它会一直等到行的末尾

显然,我们需要降低一个层次,一个角色一个角色地处理。为了达到缩进的效果,我们将用\n替换每次出现的\n

通常,对于字符翻译,我们可以使用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流程的解决方案:

这将通过显示进度的每个字符,同时在\n或\r后缩进每行


请注意,我们的交互式缩进函数比简单的\n到\n替换程序稍微复杂一些。我们还必须处理npm在进度更新和依赖关系树绘制中大量使用的回车,\r,并确保每一行从位置0开始,因此每一行旁边都有回车。\n

您在这里遇到了几个问题,大多数问题与npm处理其输出的方式有关

捕捉警告 首先请注意,npm会输出警告并更新stderr上的进度,而只有最终结果才会进入stdout。因此,为了处理警告,您必须使用以下命令将stderr重定向到stdout:

npm install 2>&1 | sed 's/^/    /'
保色 但现在将stderr管道连接到sed进程,您会注意到npm忽略了着色!然而,这是大多数命令行工具(如ls、grep等)的标准行为。。只有当输出到TTY设备(即用户,而不是文件或管道)时,它们才会输出ANSI转义颜色序列。确定文件描述符是否连接到TTY的常用方法是通过函数。事实证明,npm使用的是相同的机制

要解决着色问题,我们有两个选项:

1我们可以使用与ls、grep和其他类似的选项强制颜色输出:

npm install --color=always 2>&1 | sed 's/^/    /'
或者,2我们可以使用一个名为的工具,为任何程序/脚本运行伪造TTY输出设备:

script -feqc 'npm install' /dev/null | sed 's/^/    /'
请注意,我们不再需要将stderr重定向到stdout,脚本会为我们这样做。另外,脚本将把完整的输出保存到我们选择的文件中。在本例中,我们不需要它,所以我们使用/dev/null。顺便说一句,-f将在每次写入后刷新输出,-e将确保命令的退出代码返回到parent/shell,-q强制安静模式,无信息消息,-c cmd我们提供要运行的命令

保存进度更新 好的,现在我们已经缩进警告并保留颜色,但是我们已经丢失了进度条更新

为什么会这样?因为npm在一行中输出完整的进度。在每次进度更新时,它将移动到同一行的字符位置零!并打印新的进度。对于sed,完整的进度仅为一行,并且由于sed是面向行的,因此在任何处理和输出之前,它会一直等到行的末尾

显然,我们需要降低一个层次,一个角色一个角色地处理。为了达到缩进的效果,我们将用\n替换每次出现的\n

通常,对于字符翻译,我们可以使用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流程的解决方案:

这将通过显示进度的每个字符,同时在\n或\r后缩进每行



请注意,我们的交互式缩进函数比简单的\n到\n替换程序稍微复杂一些。我们还必须处理npm在进度更新和依赖关系树绘制中大量使用的回车,\r,并确保每一行从位置0开始,因此每一行旁边都有一个回车。\n

您确定看到的是STDOUT而不是STDERR?来确定AIG问题的答案,请尝试npm i 2>&1 | sed…@AlG部分肯定会进入STDERR。@Williampersell如果我这样做,我将不再看到在我调用npm期间显示的进度文本,但4条警告的间隔正确。然而,当npm I通过sed时,我丢失了它的彩色文本。你确定你看到的是从标准输出而不是标准输出吗?要确定AIG问题的答案,请尝试npm I 2>&1 | sed…@AlG部分肯定会进入标准输出。@williampersell如果我这样做,我将不再看到我调用的npm期间显示的进度文本,但4个警告的间隔正确。然而,当npm I的彩色文本通过sedcolor时,我丢失了它,因为它工作得很漂亮;你知道如何修复两个GIF中显示的缺少的进度条吗?为什么你更喜欢脚本而不是-color=Always?我不知道,但是如果你想要进度输出,你需要愚弄npm,使其认为它正在向TTY写入,因此,你需要脚本之类的东西。啊,我明白了……我假设如果我想复制npm的确切进度输出,用更新的进度线替换之前的进度线,我必须对输出进行额外的解析,并执行相同的文本替换操作,只是插入空格?你的答案是正确的,但我会在新行上获得更新的进度行,因此不会替换以前的进度。事实上,如果我正确理解输出,则会在正在处理的每个新任务/项目上使用新的进度行…因此,对于同一npm I任务,它会将其进度放在一行上,并按预期进行替换,但是,每一项新任务的进展都会被转移到一条新的路线上——颜色工作得很漂亮;你知道如何修复两个GIF中显示的缺少的进度条吗?为什么你更喜欢脚本而不是-color=Always?我不知道,但是如果你想要进度输出,你需要愚弄npm,使其认为它正在向TTY写入,因此,你需要脚本之类的东西。啊,我明白了……我假设如果我想复制npm的确切进度输出,用更新的进度线替换之前的进度线,我必须对输出进行额外的解析,并执行相同的文本替换操作,只是插入空格?你的答案是正确的,但我会在新行上获得更新的进度行,因此不会替换以前的进度。事实上,如果我正确理解输出,则会在正在处理的每个新任务/项目上使用新的进度行…因此,对于同一npm I任务,它会将其进度放在一行上,并按预期进行替换,但每一项新任务的进展都会被转移到一条新的路线上