I am developing a lib for docker command line in nodejs, I am still in starting face, I just tried basic docker run command using spawn in node js - everything works fine but it's not working for complex cases like the one below.
I want to run docker run --rm -it julia:0.3.6 julia -E "[x^2 for x in 1:100]" in nodejs, but I am gettting below error -
the input device is not a TTY
Docker Shell existed with status = 1
Below Code -
const
spawn = require('child_process').spawn,
dockerDeamon = spawn("docker", ["run","--rm", "-it", "julia:0.3.6", "-E", "\" [x^2 for x in 1:100]\""] );
dockerDeamon.stdout.on('data', data => {
console.log(`${data}`);
});
dockerDeamon.stderr.on('data', data => {
console.log(`${data}`);
});
dockerDeamon.on('close', code => {
console.log(`Docker Shell existed with status = ${code}`);
});
Is there any better way to execute the above script ?
You're passing the -t (--tty) flag to Docker, which tells it that it should expect the input and output to be attached to a terminal (TTY). However, when you're using spawn, you're instead attaching it to a Node.js stream in your program. Docker notices this and therefore gives the error Input device is not a TTY. Therefore, you shouldn't be using the -t flag in this case.
Also, note that you don't need nested quotes in your last argument, "\" [x^2 for x in 1:100]\"". The purpose of the quotes is to preserve the spaces and other special characters in the argument when running in a shell, but when you use spawn you're not using a shell.
So your statement should be something like:
dockerDeamon = spawn("docker", ["run","--rm", "-i", "julia:0.3.6", "julia", "-E", "[x^2 for x in 1:100]"] );
Related
I have a Node.js program where I need to, on a button click, run 2 commands in the Windows command line. For example, the process I'm trying to automate by the button click would be doable manually by going to cmd and entering the following commands:
pushd \\myserver.com\folder1\folder2 //Connect to remote server folder structure
mkdir NewFolder //Create new folder in the remote folder
I've found many resources pointing that I should use 'child_process', but I'm absolutely lost when it comes to shell scripting and am having a really hard time figuring out how to do this. Here's the code I have so far:
var cp = require('child_process');
cp.exec('pushd \\\\myserver.com\\folder1\\folder2\\', { shell: '/bin/bash' }, function(err, stdout, stderr){
if(err){
console.log(err);
}
});
But this above code just returns this error (which oddly removes the '\'s from the given dir):
{ Error: Command failed: pushd \\myserver.com\folder1\folder2\
/bin/bash: line 1: pushd: \myserver.comfolder1folder2: No such file or directory
at ChildProcess.exithandler (child_process.js:281:12)
killed: false,
code: 1,
signal: null,
cmd: 'pushd \\\\myserver.com\\folder1\\folder2\\' }
/bin/bash: line 1: pushd: \myserver.comfolder1folder2: No such file or directory
I'm really lost here and would appreciate any help. Any alternative you have to child_process may also be very helpful. Thank you!
Usually all the escape sequences used for string uses '\\' for a single backslash. It is understandable you used it here for the directory path for windows.
In JS particularly '\\' doesn't exactly work like that
'abc\
def' == 'abcdef' // true
'\a' == 'a' // true
When a '\' is not followed by a character with any special meaning, it is considered to be a LineContinuation instead.
As you can see from your error output using '\\\\myserver.com' considered '\myserver.com'. Plain workaround is to use '\\\\' for single '\' or use '/' for path separation which I'm not pretty sure if shell will execute it.
This is one of the blogs explains about it in details Link.
The shell is incorrect here:
{ shell: '/bin/bash' }
It should be:
{ shell: 'CMD.EXE' }
Because in the beginning of your post, you tell that you run 2 commands in the Windows command line, which indicates you are not using Bash, which is (usually) not installed on Windows.
I am writing an extension for vscode, and I need to get the environment variables of a process that is already running. But I wasn't able to find a way to do it.
I know how to do it in python using psutil:
for proc in psutil.process_iter(attrs=['name', 'exe']):
if proc.info['name'].lower() == 'SomeProcess.exe'.lower():
return proc.environ()
Is there something similar for javascript/nodejs?
You can use child_process module to spawn a terminal and execute the following commands wrt platform and get the variables, parse & use or write a native node module to access the proper APIs of each platform and get the output.
Windows (Using powershell, 2019 is the PID )
(Get-Process -id 2019).StartInfo.EnvironmentVariables
Linux
tr '\0' '\n' < /proc/2019/environ
Mac
ps eww -o command 2019 | tr ' ' '\n'
Thanks to https://serverfault.com/a/66366 & https://stackoverflow.com/a/28193753/12167785 & https://apple.stackexchange.com/a/254253 &
https://stackoverflow.com/a/11547409/12167785 &
https://stackoverflow.com/a/18765553/12167785
Combining with #SudhakarRS's answer:
var child = require('child_process').execFile('powershell', [
'(Get-Process SomeProcess).StartInfo.EnvironmentVariables'
], function(err, stdout, stderr) {
console.log(stdout);
});
If you want to debug it, make sure you peek at err and stderr.
Replacing SomeProcess with notepad works for me, but using notepad.exe does not.
On powershell you can get the processes with a particular name using Get-Process [process name].
So, for example, if I have 4 instances of notepad running and do Get-Process notepad, I see this:
You can get the process IDs with (Get-Process notepad).Id which returns:
You could use the same code to choose the ID:
var child = require('child_process').execFile(
'powershell',
['(Get-Process notepad).Id'],
function(err, stdout, stderr) {
var ids = stdout.split("\r\n");
ids.pop(); //remove the blank string at the end
console.log(ids);
}
);
^ which returns:
If you just want to grab the first process with a name, it's:
(Get-Process notepad)[0].StartInfo.EnvironmentVariables
^ obviously replace notepad with your process name.
Easyish way(from here, you can use something like shelljs then run:
ps faux | grep 'PROCESS_NAME'
Then extract the process id(I'm just working on a regex) and then do:
cat /proc/THE_PROCESS/environ | tr '\0' '\n'
You'll get the the env vars back as a string something like:
THEVAR=1
ANOTHERVAR=2
I reckon you just split the string by '\n' but I'm checking!
I'll update this once I figure the regex. **Are you on linux/mac or windows?
UPDATE: Check https://github.com/shelljs/shx for cross platform
There is no builtin way to do that in javascript/nodejs. If you really need to do it, then the best way is to run a command in the terminal and then parse the output to construct the object that you need.
yep:
process.env will give you what you need :)
you can read some more here.
EDIT: it will give you environment variables only for the process you're in... did I misunderstood and you want varibales of another process?
It seems for big enough stdout output node does not fire data events:
Example bash script:
#!/usr/bin/env sh
for i in {1..100000}; do
echo $i
done
Running the above script from bash should prints all numbers from 1 to 100k one number per line
However when proxying it via node's exec:
#!/usr/bin/env node --harmony --harmony_destructuring --harmony_default_parameters
const {exec} = require('child_process');
let stdout = '';
const child = exec('./tmp.sh');
child.stdout.on('data', data => {
stdout += data;
});
child.stdout.on('close', code => {
if (code) process.exit(code);
console.log(stdout.split('\n').slice(0, 3).join('\n'));
console.log('...');
console.log(stdout.split('\n').slice(-3).join('\n'));
});
For the above script, I'd expect to get:
1
2
3
...
99998
99999
100000
However when run It returns:
1
2
3
...
35984
35985
About a third of the output is truncated. Logging inside the data handler shows that only 1 data event is fired with 1 chunk
I've tried listening to the child.on('exit') event instead with the same result (also stdout.on('exit'))
It works the same when replacing exec with spawn
node --version # v5.4.1
osx 10.10
child_process.exec() buffers the standard output into a fixed size buffer. You are likely filling the buffer and thus you don't get the rest of the output.
There is a maxBuffer option you can pass to .exec() to make the buffer larger or you can use .spawn() and receive an unlimited stream of output.
See Stdout buffer issue using node child_process for related info.
Also worth reading: Difference between spawn and exec of Node.js child_process and Stdout of Node.js child_process exec is cut short.
I'm using Grunt to kick off a unit-test framework (Intern), which ultimately pipes another node.js process that I'm then using Charm to output results to the screen. I'm having to pass in the terminal size information from a Grunt config option, but it's a bit messy and I'd like to try and get the terminal size from within the piped process, but the standard process.stdout.cols/getWindowSize are simply unavailable as the piped process doesn't register as TTY (although Charm works fine with it all).
Any suggestions?
EDIT Just to be clear here ... the Grunt JavaScript file is running in the main node.js process, but the file I'm attempting to retrieve this info from (and where I'm therefore running people's suggested commands) is in a spawned child process.
Try these:
tput cols tells you the number of columns.
tput lines tells you the number of rows.
echo -e "lines\ncols"|tput -S to get both the lines and cols
There's stty, from coreutils:
$ stty size #60 120 <= sample output
While running the below code in terminal prints the cols:
var sys = require('sys')
var exec = require('child_process').exec;
function puts(error, stdout, stderr) { sys.puts(stdout) }
exec("tput cols", puts);
The pty.js module can make a child act like a regular terminal.
var pty = require('pty.js');
var term = pty.spawn('bash', [], {
name: 'xterm-color',
cwd: process.env.HOME,
env: process.env
});
term.on('data', function(data) {
console.log(data);
});
term.write('ls\r');
term.resize(100, 40);
term.write('ls /\r');
console.log(term.process);
I have a file where I want to scan it, find the character '{' and create a new line, then add an IP on the new line and add a semi-cologne to the end of the line, then write to a config file.
I can accomplish this with the following sed command when running from shell:
sed -i 's/{/&\n1.1.1.1;/g' /tmp/test.conf
inside test.conf:
acl testACL{
};
the output from the command in shell shows:
acl testACL{
1.1.1.1;
};
works perfect! Now the problem is when I get nodejs to execute it:
var sys = require('sys');
var exec = require('child_process').exec;
function puts(error, stdout, stderr) { sys.puts(stdout) };
exec("sed -i 's/{/&\n1.1.1.1;/g' /tmp/test.conf",puts);
return 0;
when I run the command in console: 'nodejs test.js'
I get blank output and when I check the file, the file 'test.conf' has not been altered! why?!
Also if you're thinking 'its a permissions issue!' I've had nodejs exec command write basic echos to the test config file and it worked fine.
I have also tried the 'shelljs' module with no luck there. I have tried countless combinations for hours now with no prevail! I'm puzzled.
I think you need to escape your \n as \\n. Right now, it's getting parsed as a literal newline in the command, which is messing it up.