File: README.md
try
"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 and distinguished artifact award at OSDI'26!
Description
Quick jump: Usage | Installing | Citation | License
try lets you run a command and inspect its effects before changing your live system. try uses Linux's namespaces (via unshare) and the overlayfs union filesystem.
Please refer to the paper (OSDI'26) 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)
Getting Started
Dependencies
try relies on the following Debian packages
attr(forgetfattr)pandocandautoconf(if working from a GitHub clone)
In cases where overlayfs doesn't work on nested mounts, you will need either
mergerfs or unionfs. 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:
bashexpectcurl
try has been tested on the following distributions:
Ubuntu 20.04 LTSor laterDebian 12Fedora 38Centos 9 Stream 5.14.0-325.el9Arch 6.1.33-1-ltsAlpine 6.1.34-1-ltsRocky 9 5.14.0-284.11.1.el9_2SteamOS 3.4.8 5.13.0-valve36-1-neptune
Note that try will only work on Linux
5.11
or higher for overlayfs to work in a user namespace.
Installing
There are three ways to install try:
The quick and janky way: grab the script. You only need the
tryscript. Put it in yourPATHand you're ready to go. You won't have documentation or utility support, but it should work as is.By cloning the repository. Run the following:
$ git clone https://github.com/binpash/try.git
$ autoconf && ./configure && make && sudo make installYou 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.
- By using a source distribution. Download
try-XXX.tgzfrom the release page. You can get the latest prerelease by downloadingtry-latest.tgz. You can then install similarly to the above:
$ git clone https://github.com/binpash/try.git
$ ./configure && make && sudo make installThe 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, you can install it with your preferred AUR helper:
yay -S tryor manually:
git clone https://aur.archlinux.org/try.git
cd try
makepkg -sicNix/NixOS
try is present in nixpkgs and maintained by us.
nix-shell -p tryExample 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:
$ try pip3 install libdash
... # output continued belowBy default, try will ask you to commit the changes made at the end of its execution.
...
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] ySometimes, 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.
$ try -n "curl https://sh.rustup.rs | sh"
/tmp/tmp.uCThKq7LBKAlternatively, you can specify your own existing overlay directory using the -N [dir] flag:
$ mkdir rustup-sandbox
$ try -N rustup-sandbox "curl https://sh.rustup.rs | sh"
$ ls rustup-sandbox
temproot upperdir workdirAs 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:
~/try/rustup-sandbox/upperdir$ du -hs .
1.2G .You can inspect the changes made inside a given overlay directory using try:
$ 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:
$ try commit rustup-sandboxYou 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:
$ 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 - sandbox3In 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 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 ina being printed. We are currently not planning on resolving this
behavior.
Please also report any issue you run into while using the future branch!
See Also
checkinstall (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:
@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.
File: completions/README.md
Shell completions
This directory holds completions for the bash shell.
You can apply completions locally by running:
source try.bashAlternatively, to enable try shell completion by default, consider adding the following line to your .bashrc:
source /completions/try.bashTo enable try shell completion for all users,
consider copying the bash completion script to the /etc/bash_completion.d/ directory:
sudo cp try.bash /etc/bash_completion.d/File: docs/try.1.md
% TRY(1) try 0.2.0 | Do, or do not. There is no try.
% The PaSh Authors
NAME
try - run a command in an overlay
SYNOPSIS
| try [-ny] [-E PATTERN] [-I PATTERN] [-i PATH] [-N DIR] [-U PATH] [-L LOWER_DIRS] CMD [ARG ...]
| try summary [DIR]
| try commit [DIR]
| try explore
| try -v
| try -h
DESCRIPTION
try lets you run a command inside an overlay without modifying the state of the filesystem.
While using try you can choose to commit the result to the filesystem or completely discard it without any side-effect to the main file system.
You can also choose your own shell when running try. try will run your command within your login shell by default; you can override this by setting the TRY_SHELL variable to the absolute path of a shell to use
Flags
-n
: Don't commit or prompt for commit. Just return the overlay directory. Overrides -y.
-y
: Assume yes to all prompts. Overrides -n.
-v
: Show version information (and exit).
-h
: Show a usage message (and exit).
-x
: Prevent network access (by unsharing the network namespace).
Options
-E PATTERN
: Exclude paths that match PATTERN on summary and commit. This option can be passed multiple times; the patterns given will be used in a pattern file passed to grep -v.
-I PATTERN
: Include only paths that match PATTERN on summary and commit. This option can be passed multiple times; the patterns given will be used in a pattern file passed to grep.
-i PATH
: Hide PATH inside the sandbox. Relative paths are resolved from the directory where try is invoked. This option can be passed multiple times.
-N DIR
: Specify DIR as the overlay directory (implies -n). The use of -N also implies that DIR already exists.
-U PATH
: Use the unionfs helper implementation defined in the PATH (e.g., mergerfs, unionfs-fuse) instead of the default.
This option is recommended in case OverlayFS fails.
-L LOWER_DIRS
: Specify a colon-separated list of directories to be used as lower directories for the overlay, formatted as "dir1:dir2:...:dirn" (implies -n).
Subcommands
try summary DIR
: Show the summary for the overlay in DIR.
try commit DIR
: Commit the overlay in DIR.
try explore
: Run in interactive mode, i.e., start a shell in the overlay.
Arguments
CMD
: Specifies the command to execute inside the overlay.
ARG
: The arguments of CMD.
EXIT STATUS
0
: Command ran successfully.
1
: Consistency error/failure.
2
: Input or other internal error.
EXAMPLES
The general workflow is to try a command before committing its results to your workspace.
To uncompress a gzip file, you can invoke try as follows
try gunzip file.txt.gzBy default, try will ask you to commit the changes made at the end of its execution.
Changes detected in the following files:
/tmp/tmp.0caZdxnHuR/upperdir/home/me/file.txt
/tmp/tmp.0caZdxnHuR/upperdir/home/me/file.txt.gz
Commit these changes? [y/N] ySometimes, you might want to pre-execute a command and commit its result at a later time. Invoking try with the -n flag will return the overlay directory, without committing the result.
try -n gunzip file.txt.gzAlternatively, you can specify your own overlay directory as follows (note that try_dir already exists):
try -N try_dir gunzip file.txt.gzTo use multiple lower directories for overlay (by merging them), you can use the -L 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:
try -L /lowerdir1:/lowerdir2:/lowerdir3 gunzip file.txt.gzYou can inspect the changes made inside a given overlay directory:
try summary try_dirYou can also choose to commit the overlay directory contents:
try commit try_dirSEE ALSO
checkinstall(1), chroot(1), unshare(1), mount_namespaces(7), namespaces(7), mount(8)
BUGS
See
https://github.com/binpash/try/issues.
LICENSE
Copyright (c) 2023 The PaSh Authors. MIT licensed.
File: scripts/README.md
This directory holds utility scripts used in development of try.
The lint.sh script runs basic file linting.
The run_tests.sh script runs the test suite.
File: utils/README.md
This directory contains C code (GNU dialect, Linux only) that summarizes and commits the changes from try, in try-summary and try-commit, respectively.
You do not need these utilities to use try, which has POSIX shell fallback implementations.
Every time try starts up, it looks for these executables on its path; if found, it will use them---otherwise it will use the shell fallbacks. The shell fallbacks are not quite as robust as these utilities and may behave strangely on files with newlines in their names.
Development
These are meant to short, simple scripts.
In order to make sure that we keep them parallel, both files are annotated with TRYCASE(changed, local) forms in comments that identify which case is being handled.
Here changed and local adhere to lf the following grammar:
changed ::= f | opaque | whiteout
local ::= f | *
f ::= file | dir | symlink | nonexistThe script ../scripts/check_trycase.sh will check to make sure that all cases are considered (excepting TRYCASE(opaque, nonexist), which should not happen). If new files need to do a case analysis on how changed files and local files relate, annotate each case with // TRYCASE(cf, lf) and add a check_file call to the check_trycase.sh script.
Assumptions
We rely on user.overlay.opaque to be set for opaque directories, which we can assume will happen because try sets -o userxattr when it mounts the overlay.
We do not handle redirect directories, instead relying on cp/mv to do the copying.
We have not seen user.overlay.whiteout in practice---perhaps it only gets made when you can't mknod a (0,0) character device on the upperdir filesystem?