# try

<img src="docs/try_logo.png" alt="try logo" width="100" height="130">

"Do, or do not. There is no try."

We're setting out to change that: `try cmd` and commit---or not.

**News**: `try` received a [best paper](https://www.usenix.org/conferences/best-papers?taxonomy_vocabulary_1_tid=2026&title_1=OSDI) **and** distinguished artifact award at [OSDI'26](https://www.usenix.org/conferences/best-papers)!

## Description
[![Main workflow](https://github.com/binpash/try/actions/workflows/test.yaml/badge.svg)](https://github.com/binpash/try/actions/workflows/test.yaml)
[![License](https://img.shields.io/badge/License-MIT-blue)](#license)
[![issues - try](https://img.shields.io/github/issues/binpash/try)](https://github.com/binpash/try/issues)

Quick jump: [Usage](#example-usage) | [Installing](#installing) | [Citation](#citation) | [License](#license)

`try` lets you run a command and inspect its effects before changing your live system. `try` uses Linux's [namespaces (via `unshare`)](https://docs.kernel.org/userspace-api/unshare.html) and the [overlayfs](https://docs.kernel.org/filesystems/overlayfs.html) union filesystem.
Please refer to the [paper (OSDI'26)](https://www.usenix.org/conference/osdi26/presentation/lamprou) for a more detailed description of its design and implementation.

Please note that `try` is a semisolate (as opposed to a sandbox), and should not be used to execute
commands that you don't already trust on your system, (i.e. network calls are all allowed)

<img src="docs/try_pip_install_example.gif" alt="try gif">

## Getting Started

### Dependencies

`try` relies on the following Debian packages

* `attr` (for `getfattr`)
* `pandoc` and `autoconf` (if working from a GitHub clone)

In cases where overlayfs doesn't work on nested mounts, you will need either
[mergerfs](https://github.com/trapexit/mergerfs) or [unionfs](https://github.com/rpodgorny/unionfs-fuse). `try` should be able to autodetect them, but you can specify the path to mergerfs or unionfs with -U (e.g. `try -U ~/.local/bin/unionfs`)

To run `try`'s test suite (`scripts/run_tests.sh`), you will need:

* `bash`
* `expect`
* `curl`

`try` has been tested on the following distributions:

* `Ubuntu 20.04 LTS` or later
* `Debian 12`
* `Fedora 38`
* `Centos 9 Stream 5.14.0-325.el9`
* `Arch 6.1.33-1-lts`
* `Alpine 6.1.34-1-lts`
* `Rocky 9 5.14.0-284.11.1.el9_2`
* `SteamOS 3.4.8 5.13.0-valve36-1-neptune`

*Note that try will only work on [Linux
5.11](https://github.com/torvalds/linux/commit/92dbc9dedccb9759c7f9f2f0ae6242396376988f)
or higher for overlayfs to work in a user namespace.*

### Installing

There are three ways to install try:

1. **The quick and janky way: grab the script.** You only need the [`try` script](https://raw.githubusercontent.com/binpash/try/main/try). Put it in your `PATH` and you're ready to go. You won't have documentation or utility support, but it should work as is.

2. **By cloning the repository.** Run the following:
```ShellSession
$ git clone https://github.com/binpash/try.git
$ autoconf && ./configure && make && sudo make install
```
You should now have a fully featured `try`, including the support utilities (which should help `try` run faster) and manpage. Run `make test` to confirm that everything works.

3. **By using a source distribution.** Download `try-XXX.tgz` from [the release page](https://github.com/binpash/try/releases). You can get the latest prerelease by downloading [`try-latest.tgz`](https://github.com/binpash/try/releases/download/latest/try-latest.tgz). You can then install similarly to the above:
```ShellSession
$ git clone https://github.com/binpash/try.git
$ ./configure && make && sudo make install
```

The repository and source distribution are slightly different: the repository does not include the `configure` script (generated by `autoconf`) or the manpage (generated by `pandoc`), but the source distribution does.

#### Arch Linux

`try` is on the [AUR](https://aur.archlinux.org/packages/try), you can install it with your preferred AUR helper:

```shellsession
yay -S try
```

or manually:

```shellsession
git clone https://aur.archlinux.org/try.git
cd try
makepkg -sic
```

#### Nix/NixOS

`try` is present in [nixpkgs](https://search.nixos.org/packages?channel=unstable&show=try&from=0&size=50&sort=relevance&type=packages&query=try) and maintained by us.

```shellsession
nix-shell -p try
```

## Example Usage

`try` is a higher-order command, like `xargs`, `exec`, `nohup`, or `find`. For example, to install a package via `pip3`, you can invoke `try` as follows:

```ShellSession
$ try pip3 install libdash
... # output continued below
```

By default, `try` will ask you to commit the changes made at the end of its execution.

```ShellSession
...
Defaulting to user installation because normal site-packages is not writeable
Collecting libdash
  Downloading libdash-0.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (254 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 254.6/254.6 KB 2.1 MB/s eta 0:00:00
Installing collected packages: libdash
Successfully installed libdash-0.3.1
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv

Changes detected in the following files:

/tmp/tmp.zHCkY9jtIT/upperdir/home/gliargovas/.local/lib/python3.10/site-packages/libdash/ast.py (modified/added)
/tmp/tmp.zHCkY9jtIT/upperdir/home/gliargovas/.local/lib/python3.10/site-packages/libdash/_dash.py (modified/added)
/tmp/tmp.zHCkY9jtIT/upperdir/home/gliargovas/.local/lib/python3.10/site-packages/libdash/__init__.py (modified/added)
/tmp/tmp.zHCkY9jtIT/upperdir/home/gliargovas/.local/lib/python3.10/site-packages/libdash/__pycache__/printer.cpython-310.pyc (modified/added)
/tmp/tmp.zHCkY9jtIT/upperdir/home/gliargovas/.local/lib/python3.10/site-packages/libdash/__pycache__/ast.cpython-310.pyc (modified/added)
<snip>

Commit these changes? [y/N] y
```

Sometimes, you might want to pre-execute a command and commit its result at a later time. Running `try -n` will print the overlay directory on STDOUT without committing the result.

```ShellSession
$ try -n "curl https://sh.rustup.rs | sh"
/tmp/tmp.uCThKq7LBK
```

Alternatively, you can specify your own existing overlay directory using the `-N [dir]` flag:

```ShellSession
$ mkdir rustup-sandbox
$ try -N rustup-sandbox "curl https://sh.rustup.rs | sh"
$ ls rustup-sandbox
temproot  upperdir  workdir
```

As you can see from the output above, `try` has created an overlay environment in the `rustup-sandbox` directory.

Manually inspecting upperdir reveals the changes to the files made inside the overlay during the execution of the previous command with *try*:

```ShellSession
~/try/rustup-sandbox/upperdir$ du -hs .
1.2G    .
```

You can inspect the changes made inside a given overlay directory using `try`:

```ShellSession
$ try summary rustup-sandbox/ | head

Changes detected in the following files:

rustup-sandbox//upperdir/home/ubuntu/.profile (modified/added)
rustup-sandbox//upperdir/home/ubuntu/.bashrc (modified/added)
rustup-sandbox//upperdir/home/ubuntu/.rustup/update-hashes/stable-x86_64-unknown-linux-gnu (modified/added)
rustup-sandbox//upperdir/home/ubuntu/.rustup/settings.toml (modified/added)
rustup-sandbox//upperdir/home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/libstd-8389830094602f5a.so (modified/added)
rustup-sandbox//upperdir/home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/etc/lldb_commands (modified/added)
rustup-sandbox//upperdir/home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/etc/gdb_lookup.py (modified/added)
```

You can also choose to commit the overlay directory contents:

```ShellSession
$ try commit rustup-sandbox
```

You can also run `try explore` to open your current shell in try, or `/try
explore /tmp/tmp.X6OQb5tJwr` to explore an existing sandbox.

To specify multiple lower directories for overlay (by merging them together), you can use the `-L` (implies `-n`) flag followed by a colon-separated list of directories. The directories on the left have higher precedence and can overwrite the directories on the right:

```ShellSession
$ try -N /tmp/sandbox1 "echo 'File 1 Contents - sandbox1' > file1.txt"
$ try -N /tmp/sandbox2 "echo 'File 2 Contents - sandbox2' > file2.txt"
$ try -N /tmp/sandbox3 "echo 'File 2 Contents - sandbox3' > file2.txt"

# Now use the -L flag to merge both sandbox directories together, with sandbox3 having precedence over sandbox2
$ try -L "/tmp/sandbox3:/tmp/sandbox2:/tmp/sandbox1" "cat file1.txt file2.txt"
File 1 Contents - sandbox1
File 2 Contents - sandbox3
```

In this example, `try` will merge `/sandbox1`, `/sandbox2` and `/sandbox3` together before mounting the overlay. This way, you can combine the contents of multiple `try` sandboxes.


## Known Issues
Any command that interacts with other users/groups will fail since only the
current user's UID/GID are mapped. However, the [future
branch](https://github.com/binpash/try/tree/future) has support for uid/mapping;
please refer to the that branch's readme for installation instructions for the
uid/gidmapper (root access is required for installation).

Shell quoting may be unintuitive, you may expect `try bash -c "echo a"` to work,
however, try will actually execute `bash -c echo a`, which will not result in
`a` being printed. [We are currently not planning on resolving this
behavior.](https://github.com/binpash/try/issues/155#issuecomment-2078556237)

Please also report any issue you run into while using the future branch!

## See Also

[checkinstall](http://checkinstall.izto.org/) (unmaintained)

checkinstall keeps track of all the files created or modified by your
installation script, builds a standard binary package and installs it in your
system. This package can then be easily installed, managed, and removed using
the package manager of your Linux distribution. It helps in maintaining a clean
and organized system by keeping track of installed software and its
dependencies.

## Citation

If you use `try`, please cite the paper:

```bibtex
@inproceedings{try:osdi:2026,
  title = {Controlling Opaque-Component Effects with Semisolates and Try},
  author = {Lamprou, Evangelos and Zhu, Tianyu (Ezri) and Jin, Di and Ntousakis, Grigoris and Liargkovas, Georgios and Eng, Calvin and Kallas, Konstantinos and Greenberg, Michael and Vasilakis, Nikos},
  year = {2026},
  booktitle = {20th USENIX Symposium on Operating Systems Design and Implementation (OSDI 26)},
  publisher = {USENIX Association},
  url = {https://www.usenix.org/conference/osdi26/presentation/lamprou},
}

```

## License

This project is licensed under the MIT License - see LICENSE for details.

Copyright (c) 2023 The PaSh Authors.
