lgarron / printable-shell-command

A helper class to construct shell commands in a way that allows printing them.

Repository from Github https://github.comlgarron/printable-shell-commandRepository from Github https://github.comlgarron/printable-shell-command

printable-shell-command

A helper class to construct shell commands in a way that allows printing them.

The goal is to make it easy to print commands that are being run by a program, in a way that makes it easy and safe for a user to copy-and-paste.

Goals

  1. Security — the printed commands should be possible to use in all shells without injection vulnerabilities.
  2. Fidelity — the printed command must match the arguments provided.
  3. Aesthetics — the command is pretty-printed to make it easy to read and to avoid escaping/quoting simple arguments where humans usually would not.

Point 1 is difficult, and maybe even impossible. This library will do its best, but what you don't know can hurt you.

Usage

Construct a command by providing a command string and a list of arguments. Each argument can either be an individual string, or a "pair" list containing two strings (usually a command flag and its argument). Pairs do not affect the semantics of the command, but they affect pretty-printing.

// example.ts
import { PrintableShellCommand } from "printable-shell-command";

export const command = new PrintableShellCommand("ffmpeg", [
  ["-i", "./test/My video.mp4"],
  ["-filter:v", "setpts=2.0*PTS"],
  ["-filter:a", "atempo=0.5"],
  "./test/My video (slow-mo).mov",
]);

command.print();

This prints:

ffmpeg \
  -i './test/My video.mp4' \
  -filter:v 'setpts=2.0*PTS' \
  -filter:a atempo=0.5 \
  './test/My video (slow-mo).mov'

Spawn a process in node

import { PrintableShellCommand } from "printable-shell-command";
import { spawn } from "node:child_process";

const command = new PrintableShellCommand(/* … */);
const child_process = spawn(...command.toCommandWithFlatArgs()); // Note the `...`

// or directly
await command.spawn().success;
await command.spawnTransparently().success;
await command.spawnDetached().success;

Spawn a process in bun

import { PrintableShellCommand } from "printable-shell-command";
import { spawn } from "bun";

const command = new PrintableShellCommand(/* … */);
await spawn(command.toFlatCommand()).exited;

// or directly
await command.bun.spawnBun().success;
await command.bun.spawnBunInherit().success;

Protections

Any command or argument containing the following characters is quoted and escaped:

  • (space character)
  • " (double quote)
  • ' (single quote)
  • ` (backtick)
  • |
  • $
  • *
  • ?
  • >
  • <
  • (
  • )
  • [
  • ]
  • {
  • }
  • &
  • \
  • ;
  • #

Additionally, a command is escaped if it contains an =.

Escaping is done as follows:

  • The command is single-quoted.
  • Backslashes and single quotes are escaped.

About

A helper class to construct shell commands in a way that allows printing them.


Languages

Language:TypeScript 97.4%Language:Makefile 2.6%