deno task
deno task
provides a cross-platform way to define and execute custom commands
specific to a codebase.
To get started, define your commands in your codebase's
Deno configuration file under a
"tasks"
key.
For example:
{
"tasks": {
"data": "deno task collect && deno task analyze",
"collect": "deno run --allow-read=. --allow-write=. scripts/collect.js",
"analyze": "deno run --allow-read=. scripts/analyze.js"
}
}
Listing tasks
To get an output showing all the defined tasks, run:
deno task
Executing a task
To execute a specific task, run:
deno task task-name [additional args]...
In the example above, to run the data
task we would do:
deno task data
Specifying the current working directory
By default, deno task
executes commands with the directory of the Deno
configuration file (ex. deno.json) as the current working directory. This
allows tasks to use relative paths and continue to work regardless of where in
the directory tree you happen to execute the deno task from. In some scenarios,
this may not be desired and this behavior can be overridden with the INIT_CWD
environment variable.
INIT_CWD
will be set with the full path to the directory the task was run in,
if not already set. This aligns with the same behavior as npm run
.
For example, the following task will change the current working directory of the
task to be in the same directory the user ran the task from and then output the
current working directory which is now that directory (remember, this works on
Windows too because deno task
is cross-platform).
{
"tasks": {
"my_task": "cd $INIT_CWD && pwd"
}
}
Getting directory deno task
was run from
Since tasks are run using the directory of the Deno configuration file as the
current working directory, it may be useful to know the directory the
deno task
was executed from instead. This is possible by using the INIT_CWD
environment variable in a task or script launched from deno task
(works the
same way as in npm run
, but in a cross-platform way).
For example, to provide this directory to a script in a task, do the following (note the directory is surrounded in double quotes to keep it as a single argument in case it contains spaces):
{
"tasks": {
"start": "deno run main.ts \"$INIT_CWD\""
}
}
Syntax
deno task
uses a cross-platform shell that's a subset of sh/bash to execute
defined tasks.
Boolean lists
Boolean lists provide a way to execute additional commands based on the exit
code of the initial command. They separate commands using the &&
and ||
operators.
The &&
operator provides a way to execute a command and if it succeeds (has
an exit code of 0
) it will execute the next command:
deno run --allow-read=. --allow-write=. collect.ts && deno run --allow-read=. analyze.ts
The ||
operator is the opposite. It provides a way to execute a command and
only if it fails (has a non-zero exit code) it will execute the next command:
deno run --allow-read=. --allow-write=. collect.ts || deno run play_sad_music.ts
Sequential lists
Sequential lists are similar to boolean lists, but execute regardless of whether
the previous command in the list passed or failed. Commands are separated with a
semi-colon (;
).
deno run output_data.ts ; deno run --allow-net server.ts
Async commands
Async commands provide a way to make a command execute asynchronously. This can
be useful when starting multiple processes. To make a command asynchronous, add
an &
to the end of it. For example the following would execute
sleep 1 && deno run --allow-net client.ts
and deno run --allow-net server.ts
at the same time:
sleep 1 && deno run --allow-net client.ts & deno run --allow-net server.ts
Unlike in most shells, the first async command to fail will cause all the other
commands to fail immediately. In the example above, this would mean that if the
client command fails then the server command will also fail and exit. You can
opt out of this behavior by adding || true
to the end of a command, which will
force a 0
exit code. For example:
deno run --allow-net client.ts || true & deno run --allow-net server.ts || true
Environment variables
Environment variables are defined like the following:
export VAR_NAME=value
Here's an example of using one in a task with shell variable substitution and then with it being exported as part of the environment of the spawned Deno process (note that in the JSON configuration file the double quotes would need to be escaped with backslashes):
export VAR=hello && echo $VAR && deno eval "console.log('Deno: ' + Deno.env.get('VAR'))"
Would output:
hello
Deno: hello
Setting environment variables for a command
To specify environment variable(s) before a command, list them like so:
VAR=hello VAR2=bye deno run main.ts
This will use those environment variables specifically for the following command.
Shell variables
Shell variables are similar to environment variables, but won't be exported to spawned commands. They are defined with the following syntax:
VAR_NAME=value
If we use a shell variable instead of an environment variable in a similar example to what's shown in the previous "Environment variables" section:
VAR=hello && echo $VAR && deno eval "console.log('Deno: ' + Deno.env.get('VAR'))"
We will get the following output:
hello
Deno: undefined
Shell variables can be useful when we want to re-use a value, but don't want it available in any spawned processes.
Exit status variable
The exit code of the previously run command is available in the $?
variable.
# outputs 10
deno eval 'Deno.exit(10)' || echo $?
Pipelines
Pipelines provide a way to pipe the output of one command to another.
The following command pipes the stdout output "Hello" to the stdin of the spawned Deno process:
echo Hello | deno run main.ts
To pipe stdout and stderr, use |&
instead:
deno eval 'console.log(1); console.error(2);' |& deno run main.ts
Command substitution
The $(command)
syntax provides a way to use the output of a command in other
commands that get executed.
For example, to provide the output of getting the latest git revision to another command you could do the following:
deno run main.ts $(git rev-parse HEAD)
Another example using a shell variable:
REV=$(git rev-parse HEAD) && deno run main.ts $REV && echo $REV
Negate exit code
To negate the exit code, add an exclamation point and space before a command:
# change the exit code from 1 to 0
! deno eval 'Deno.exit(1);'
Redirects
Redirects provide a way to pipe stdout and/or stderr to a file.
For example, the following redirects stdout of deno run main.ts
to a file
called file.txt
on the file system:
deno run main.ts > file.txt
To instead redirect stderr, use 2>
:
deno run main.ts 2> file.txt
To redirect both stdout and stderr, use &>
:
deno run main.ts &> file.txt
To append to a file, instead of overwriting an existing one, use two right angle brackets instead of one:
deno run main.ts >> file.txt
Suppressing either stdout, stderr, or both of a command is possible by
redirecting to /dev/null
. This works in a cross-platform way including on
Windows.
# suppress stdout
deno run main.ts > /dev/null
# suppress stderr
deno run main.ts 2> /dev/null
# suppress both stdout and stderr
deno run main.ts &> /dev/null
Or redirecting stdout to stderr and vice-versa:
# redirect stdout to stderr
deno run main.ts >&2
# redirect stderr to stdout
deno run main.ts 2>&1
Input redirects are also supported:
# redirect file.txt to the stdin of gzip
gzip < file.txt
Note that redirecting multiple redirects is currently not supported.
Cross-platform shebang
Starting in Deno 1.42, deno task
will execute scripts that start with
#!/usr/bin/env -S
the same way on all platforms.
For example:
#!/usr/bin/env -S deno run
console.log("Hello there!");
{
"tasks": {
"hi": "./script.ts"
}
}
Then on a Windows machine:
> pwd
C:\Users\david\dev\my_project
> deno task hi
Hello there!
Glob expansion
Glob expansion is supported in Deno 1.34 and above. This allows for specifying globs to match files in a cross-platform way.
# match .ts files in the current and descendant directories
echo **/*.ts
# match .ts files in the current directory
echo *.ts
# match files that start with "data", have a single number, then end with .csv
echo data[0-9].csv
The supported glob characters are *
, ?
, and [
/]
.
Built-in commands
deno task
ships with several built-in commands that work the same out of the
box on Windows, Mac, and Linux.
cp
- Copies files.mv
- Moves files.rm
- Remove files or directories.- Ex:
rm -rf [FILE]...
- Commonly used to recursively delete files or directories.
- Ex:
mkdir
- Makes directories.- Ex.
mkdir -p DIRECTORY...
- Commonly used to make a directory and all its parents with no error if it exists.
- Ex.
pwd
- Prints the name of the current/working directory.sleep
- Delays for a specified amount of time.- Ex.
sleep 1
to sleep for 1 second,sleep 0.5
to sleep for half a second, orsleep 1m
to sleep a minute
- Ex.
echo
- Displays a line of text.cat
- Concatenates files and outputs them on stdout. When no arguments are provided it reads and outputs stdin.exit
- Causes the shell to exit.head
- Output the first part of a file.unset
- Unsets environment variables.xargs
- Builds arguments from stdin and executes a command.
If you find a useful flag missing on a command or have any suggestions for additional commands that should be supported out of the box, then please open an issue on the deno_task_shell repo.
Note that if you wish to execute any of these commands in a non-cross-platform
way on Mac or Linux, then you may do so by running it through sh
:
sh -c <command>
(ex. sh -c cp source destination
).
package.json support
deno task
falls back to reading from the "scripts"
entries in a package.json
file if it is discovered. Note that Deno does not respect or support any npm
life cycle events like preinstall
or postinstall
—you must explicitly run the
script entries you want to run (ex.
deno cache main.ts && deno task postinstall
).