Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash + Node.js + stdin/stdout redirection: error "not a tty"

This problem may be Windows-specific. I have not tested it on Linux or Mac.

I use:

  • Windows 7 64 Bit
  • Node.js 8.1.3
  • Git for Windows 2.8.1, including GNU bash, version 4.3.42(5)-release

node my-cli.js > foo.txt: Error output is not a tty

node my-cli.js < foo.txt: Error input is not a tty.

like image 400
Marco Eckstein Avatar asked Jul 14 '17 23:07

Marco Eckstein


4 Answers

Create a file my-cli:

#!/bin/sh

node "path/to/my-cli.js" "$@"
exit $?

Call ./my-cli > foo.txt or ./my-cli < foo.txt.

This also works with arguments: ./my-cli --answer 42 > foo.txt

like image 195
Marco Eckstein Avatar answered Sep 16 '22 15:09

Marco Eckstein


This happens because Git for Windows on default setup will source this file /etc/profile.d/aliases.sh which will do alias node="winpty node.exe", which is required for interactive usage with node (as well as other programs like python,...). So when you invoke node xxx <yyy >zzz, your shell is actually calling winpty node xxx under the hood

winpty works by starting the winpty-agent.exe process with a new, hidden console window, which bridges between the console API and terminal input/output escape codes. It polls the hidden console's screen buffer for changes and generates a corresponding stream of output.

, but the side effect is that the stdin and stdout is not recognised as tty's.

So when piping or redirecting, you would want to invoke the node binary itself and not the alias. There are some ways to achieve this:

  1. Wrap in a shell script which would directly call node since non-interactive shell does not source the aliases.sh file. See the other answers (both sh and bash work)

  2. Call with
    env node my-cli.js > foo.txt or
    command node my-cli.js > foo.txt

env runs the command in a default environment, the effect is like that of the above method; while command is a bash shell built-in that is used to bypass aliases.

  1. Call like
    \node my-cli.js > foo.txt or
    'node' my-cli.js > foo.txt or
    "node" my-cli.js > foo.txt

The backslash and quotation are constructs to explicitly bypass aliasing.

  1. Call using
    node.exe my-cli.js > foo.txt or
    /full/path/to/node my-cli.js > foo.txt or
    relative/path/to/node my-cli.js > foo.txt

The alias is for node, not node.exe nor path/to/node, which still points to the actual binary.

A way to expand on these solutions is to write a wrapper script that detects piping/redirection (which is in itself a whole other challenge tbh) which will decide to use winpty or not.

like image 24
Phu Ngo Avatar answered Sep 17 '22 15:09

Phu Ngo


sh -c 'node my-cli.js' > foo.txt works for me

like image 27
Konstantin Pelepelin Avatar answered Sep 17 '22 15:09

Konstantin Pelepelin


Since I'm here in 2022 having this same issue in GitBash, one of the other answers pointed me to the simplest solution.

Since you're already typing

node my-cli.js > foo.txt

All you need to do is change node to node.exe and leave everything else the same.

node.exe my-cli.js > foo.txt

The aliases answer above is what made me try this. node is aliased, but node.exe is not aliased, so it works the way you want it to work.

like image 27
Laura Avatar answered Sep 16 '22 15:09

Laura