# Bash Apps

If you have not already, you should install the [DNAnexus SDK](/downloads.md) and walk through the [Intro to Building Apps](/developer/apps/intro-to-building-apps.md) tutorial.

Bash apps are the simplest apps you can create on DNAnexus. They include a shell script which runs on a virtual machine on the cloud. The script, written by the app developer, handles downloading inputs, processing, and uploading outputs.

## Downloading and Using File Inputs

Two methods are available to download inputs: one by one, or all at once.

To download all inputs at once (recommended), use the `dx-download-all-inputs` utility. Add `--parallel` to allow multiple downloads in parallel: `dx-download-all-inputs --parallel`.

Inputs are downloaded to a folder called "in" under the home folder. Each input is placed under its own subfolder `~/in/name_of_input_field/`, named after the input field. Files keep their original filenames as supplied by the user who launched the applet.

For example, if your applet defines a file input called `mappings` and a user runs it with a file called `SRR001.bam`, it is downloaded into `~/in/mappings/SRR001.bam`.

The system defines the following helper bash variables, which you can use in your applet:

| Bash variable      |                        Content                        |
| ------------------ | :---------------------------------------------------: |
| `$mappings_path`   |               `~/in/mappings/SRR001.bam`              |
| `$mappings_name`   |                      `SRR001.bam`                     |
| `$mappings_prefix` |                        `SRR001`                       |
| `$mappings`        | `{"$dnanexus_link": "file-F77Bp7002302Zb343BF1FpG0"}` |

{% hint style="info" %}
The variable `$mappings_prefix` is automatically computed by the system by starting from the filename and removing any suffixes that match the patterns specified in `dxapp.json` for this input field.
{% endhint %}

To download inputs one by one, use the following syntax:

```shell
# Download the input file to the current working directory
dx download "$name_of_input_field"
```

This downloads the file to the current working directory, keeping the original filename as supplied by the user who launched the applet. You can use the `"$xxxxxx_name"` variable (as shown in the table above) to refer to that filename.

To name the local file using a different name than the original filename, use the following syntax:

```shell
# Download the input file and save it as 'local_filename'
dx download "$name_of_input_field" -o local_filename
```

To stream the local file and pipe it to another command, use the following syntax:

```shell
# Stream the input file and pipe it to another command
dx cat "$name_of_input_field" | command
```

You can combine these strategies. For example, you can download or stream some inputs one by one, and the rest all at once, using the following syntax:

```shell
# Download all inputs except the specified ones
dx-download-all-inputs --except name_of_input_field1 --except name_of_input_field2

# Download a specific input file
dx download "$name_of_input_field1"

# Stream another input file and pipe it to a command
dx cat "$name_of_input_field2" | command
```

### Downloading Inputs Using dx-mount-all-inputs

An alternative to `dx-download-all-inputs` is the `dx-mount-all-inputs` command-line utility. You can use it by adding this line to your `script.sh`:

```shell
dx-mount-all-inputs
```

{% hint style="info" %}
`dxfuse` is required for the `dx-mount-all-inputs` to work. You can [download the `dxfuse` binary from GitHub](https://github.com/dnanexus/dxfuse/releases) and add it to `./resources/usr/bin/dxfuse`.
{% endhint %}

`dx-mount-all-inputs` uses the same directory structure as illustrated above for `dx-download-all-inputs`, except that the files are mounted to the respective location rather than downloaded. When using `dx-mount-all-inputs`, input files do not take up local storage because they are mounted using Linux FUSE technology and streamed behind the scenes transparently when accessed.

## Uploading Outputs

Two methods are available to upload outputs: one by one, or all at once.

To upload outputs one by one, use the following syntax:

```shell
# Upload a file and capture its file ID
id=$(dx upload /path/to/local/file --brief)

# Register the uploaded file as an output
dx-jobutil-add-output name_of_output_field "$id"
```

If you want the uploaded file to have a different name than the local file, add the following to the `dx upload` command:

```shell
# Upload a file with a different remote filename
dx upload /path/to/local/file --brief --path remote_filename
```

If you want the uploaded file to appear under a subfolder in the applet outputs, add the following to the `dx upload` command:

```shell
# Upload a file to a subfolder in the output
dx upload /path/to/local/file --brief --path /subfolder/remote_filename --parents
```

If you want the uploaded file to contain metadata, for example, set a property (key/value pair), add the following to the `dx upload` command:

```shell
# Upload a file with a property (metadata)
dx upload /path/to/local/file --brief --property key=value
```

To upload all outputs at once, create a folder "out" under the home folder, and create a subfolder named after each output field. Place a file under each subfolder, and call the `dx-upload-all-outputs` utility:

```shell
# Create output subfolders for each output field
mkdir -p ~/out/name_of_output_field1/ ~/out/name_of_output_field2/

# Move files into their respective output subfolders
mv file1 ~/out/name_of_output_field1/
mv file2 ~/out/name_of_output_field2/

# Upload all outputs at once
dx-upload-all-outputs
```

If you want any uploaded file to have a different name than the local file, rename them as you move them:

```shell
# Rename file as you move it to the output subfolder
mv file1 ~/out/name_of_output_field1/renamed_file1
```

If you want any uploaded file to appear under a subfolder in the applet outputs, create the subfolder like this:

```shell
# Create a subfolder and move the file into it
mkdir -p ~/out/name_of_output_field1/subfolder/
mv file1 ~/out/name_of_output_field1/subfolder/
```

If you want the uploaded files to contain metadata, for example, set a property (key/value pair), make the following changes:

1. Install the `attr` Linux executable by specifying the `attr` Ubuntu package in your `dxapp.json`.
2. For each file, and for each key/value pair you want to attach, set the respective Linux extended file system attribute like this:

   ```shell
   # Set an extended attribute (property) on a file
   attr -s key -V value ~/out/name_of_output_field1/file1
   ```
3. Add `--xattr-properties` to the `dx-upload-all-outputs` invocation:

   ```shell
   # Upload all outputs and include extended attributes as properties
   dx-upload-all-outputs --xattr-properties
   ```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://documentation.dnanexus.com/developer/apps/bash.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
