Search code examples
node.jsterminalwgetchild-processspawn

dynamic progress bar is not display correctly when execute wget by nodejs spawn


i write a node.js code just like below sample.

i use child_process.spawn to create child process for execute command 'wget'. at the same time i redirec standard i/o of child process to standard i/o of node.js process

let cp = spawn('wget', 'some_file_url')
cp.stdin.pipe(process.stdin)
cp.stdout.pipe(process.stdout)
cp.stderr.pipe(process.stderr)

now i execute code above in node.js, everything is ok but progress bar. it just looks like this:

     0K .......... .......... .......... .......... ..........  0%  134K 5m21s
    50K .......... .......... .......... .......... ..........  0%  631K 3m14s
   100K .......... .......... .......... .......... ..........  0% 4.64M 2m12s
   150K .......... .......... .......... .......... ..........  0%  167M 99s

normally, if i execute wget command on terminal

$ wget some_file_url

a dynamic progress bar will display in output

file.tar.gz                  15%[======>                                         ]   6.69M  2.27MB/s

so, how should i do to make the progress bar display like above

environments

  • node.js: v14.16.1
  • wget: GNU Wget 1.21.2 built on darwin21.1.0

sorry

my english is poor. please excuse grammar or typing error. i'm trying my best to imporve.


Solution

  • I suspect effect you did get is due to GNU Wget thinking its' stderr was redirected to file. I do not know how to get desired effect using GNU Wget, but if you need to just download file (and are not required to do so using GNU Wget) then consider combining https with progress. Last need to be installed first, do

    npm install progress
    

    then you might use it like so (adapted from progress - download example)

    var fs = require('fs');
    var ProgressBar = require('progress');
    var https = require('https');
     
    var req = https.request({
      host: 'www.example.com',
      port: 443,
      path: '/'
    }, function (res) {
      var filePath = fs.createWriteStream('index.html');
      res.pipe(filePath);
    });
     
    req.on('response', function(res){
      var len = parseInt(res.headers['content-length'], 10);
     
      console.log();
      var bar = new ProgressBar('  downloading [:bar] :rate/bps :percent :etas', {
        complete: '=',
        incomplete: ' ',
        width: 20,
        total: len
      });
     
      res.on('data', function (chunk) {
        bar.tick(chunk.length);
      });
     
      res.on('end', function () {
        console.log('\n');
      });
    });
     
    req.end();
    

    Code do download www.example.com page and save it as index.html, note that unlike url for wget you do NOT include protocol (in this case https) in host. 443 is default port for https. / is path to resource on server (in this case: main page). Content-Length header hold information about total file size.