Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I run an arbitrary shell command from Deno?

Tags:

deno

I want to run any arbitrary bash command from Deno, like I would with a child_process in Node. Is that possible in Deno?

like image 805
Evan Conrad Avatar asked Jun 01 '20 23:06

Evan Conrad


People also ask

How do you direct the shell to execute a command in the background?

Running shell command in background using (&) sign To run a command or a script to the background, terminate it with an ampersand sign (&) at the end as shown. NOTE: Ending the command with the ampersand sign does not detach the command from you.

How do I run a shell script in R studio?

In RStudio, commands can be executed from shell scripts by pressing Ctrl + Enter .


3 Answers

In order to run a shell command, you have to use Deno.run, which requires --allow-run permissions.

There's an ongoing discussion to use --allow-all instead for running a subprocess


The following will output to stdout.

// --allow-run
const process = Deno.run({
  cmd: ["echo", "hello world"]
});

// Close to release Deno's resources associated with the process.
// The process will continue to run after close(). To wait for it to
// finish `await process.status()` or `await process.output()`.
process.close();

If you want to store the output, you'll have to set stdout/stderr to "piped"

const process = Deno.run({
  cmd: ["echo", "hello world"], 
  stdout: "piped",
  stderr: "piped"
});


const output = await process.output() // "piped" must be set
const outStr = new TextDecoder().decode(output);

/* 
const error = await p.stderrOutput();
const errorStr = new TextDecoder().decode(error); 
*/

process.close();
like image 117
Marcos Casagrande Avatar answered Oct 17 '22 12:10

Marcos Casagrande


Make sure to await status or output of the child process created with Deno.run.

Otherwise, the process might be killed, before having executed any code. For example:

deno run --allow-run main.ts
main.ts:
const p = Deno.run({
  cmd: ["deno", "run", "--allow-write", "child.ts"],
});
const { code } = await p.status(); // (*1); wait here for child to finish
p.close();
child.ts:
// If we don't wait at (*1), no file is written after 3 sec delay
setTimeout(async () => {
  await Deno.writeTextFile("file.txt", "Some content here");
  console.log("finished!");
}, 3000);

Pass arguments via stdin / stdout:

main.ts:
const p = Deno.run({
  cmd: ["deno", "run", "--allow-write", "child.ts"],
  // Enable pipe between processes
  stdin: "piped",
  stdout: "piped",
  stderr: "piped",
});
if (!p.stdin) throw Error();

// pass input to child
await p.stdin.write(new TextEncoder().encode("foo"));
await p.stdin.close();

const { code } = await p.status();
if (code === 0) {
  const rawOutput = await p.output();
  await Deno.stdout.write(rawOutput); // could do some processing with output
} else { /* error */ }
child.ts:
import { readLines } from "https://deno.land/std/io/bufio.ts"; // convenient wrapper

// read given input argument
let args = "";
for await (const line of readLines(Deno.stdin)) {
  args += line;
}

setTimeout(async () => {
  await Deno.writeTextFile("file.txt", `Some content here with ${args}`);
  console.log(`${args} finished!`); // prints "foo finished!""
}, 3000);

There is also a good example resource in Deno docs.

like image 27
ford04 Avatar answered Oct 17 '22 11:10

ford04


You can do that with the run like this:

// myscript.js
Deno.run({
  cmd: ["echo", "hello world"]
})

You'll have to --allow-run when running the script in order for this to work:

deno run --allow-run ./myscript.js
like image 4
Evan Conrad Avatar answered Oct 17 '22 12:10

Evan Conrad