Task Outputs
Declaring and evaluating task output parameters
The output section contains declarations that are exposed as outputs of the task after the successful execution of the instantiated command. An output declaration must be initialized, and its value is evaluated only after the task's command completes successfully, enabling any files generated by the command to be used to determine its value.
Example: outputs_task.wdl
version 1.1
task outputs {
input {
Int t
}
command <<<
printf ~{t} > threshold.txt
touch a.csv b.csv
>>>
output {
Int threshold = read_int("threshold.txt")
Array[File]+ csvs = glob("*.csv")
Boolean two_csvs = length(csvs) == 2
}
}Example input:
{
"outputs.t": 5
}
Example output:
{
"outputs.threshold": 5,
"outputs.two_csvs": true
}
Test config:
{
"exclude_outputs": ["outputs.csvs"]
}After the command is executed, the following outputs are expected to be found in the task execution directory:
- A file called "threshold.txt", which contains one line that consists of only an integer and whitespace.
- One or more files (as indicated by the
+postfix quantifier) with the.csvextension in the working directory that are collected into an array by theglobfunction.
See the WDL Value Serialization section for more details.
ยงFiles and Optional Outputs
File outputs are represented as string paths.
A common pattern is to use a placeholder in a string expression to construct a file name as a function of the task input. For example:
Example: file_output_task.wdl
version 1.1
task file_output {
input {
String prefix
}
command <<<
printf "hello" > ~{prefix}.hello
printf "goodbye" > ~{prefix}.goodbye
>>>
output {
Array[String] basenames = [basename("~{prefix}.hello"), basename("~{prefix}.goodbye")]
}
}Example input:
{
"file_output.prefix": "foo"
}
Example output:
{
"file_output.basenames": ["foo.hello", "foo.goodbye"]
}Another common pattern is to use the glob function to define outputs that might contain zero, one, or many files.
Example: glob_task.wdl
version 1.1
task glob {
input {
Int num_files
}
command <<<
for i in {1..~{num_files}}; do
printf ${i} > file_${i}.txt
done
>>>
output {
Array[File] outfiles = glob("*.txt")
Int last_file_contents = read_int(outfiles[num_files-1])
}
}Example input:
{
"glob.num_files": 3
}
Example output:
{
"glob.last_file_contents": 3
}
Test config:
{
"exclude_outputs": ["glob.outfiles"]
}Relative paths are interpreted relative to the execution directory, whereas absolute paths are interpreted in a container-dependent way.
Example: relative_and_absolute_task.wdl
version 1.1
task relative_and_absolute {
command <<<
mkdir -p my/path/to
printf "something" > my/path/to/something.txt
>>>
output {
String something = read_string("my/path/to/something.txt")
# The following may or may not work depending on what the execution engine
# supports.
#
# File bashrc = "/root/.bashrc"
}
runtime {
container: "ubuntu:focal"
}
}Example input:
{}
Example output:
{
"relative_and_absolute.something": "something"
}All file outputs are required to exist, otherwise the task will fail. However, an output may be declared as optional (e.g., File? or Array[File?]), in which case the value will be undefined if the file does not exist.
Example: optional_output_task.wdl
version 1.1
task optional_output {
input {
Boolean make_example2
}
command <<<
printf "1" > example1.txt
if ~{make_example2}; then
printf "2" > example2.txt
fi
>>>
output {
File example1 = "example1.txt"
File? example2 = "example2.txt"
Array[File?] file_array = ["example1.txt", "example2.txt"]
Int file_array_len = length(select_all(file_array))
}
}Example input:
{
"optional_output.make_example2": false
}
Example output:
{
"optional_output.example2": null,
"optional_output.file_array_len": 1,
"optional_output.example1": "example1.txt",
"optional_output.file_array": ["example1.txt", null]
}
Test config:
{
"exclude_outputs": ["optional_output.example1", "optional_output.file_array"]
}Executing the above task with make_example2 = true will result in the following outputs:
optional_output.example1will resolve to aFileoptional_output.example2will resolve toNoneoptional_output.file_arraywill resolve to[<File>, None]