CLI tool
binpash/try avatar
binpash/try

binpash/try: run a command, inspect its file changes, then commit or discard

Project brief: Control and manipulate a command's effects before modifying your live system.

5,495 stars81 forksShellMIT

At a glance

What is it?
binpash/try wraps a command in a Linux user namespace and an overlayfs mount so you can see what it would write to disk before it touches your live system. The design is a semisolation, not a sandbox, and it does nothing about network access or process effects.
Who is it for?
Adopt binpash/try if you administer a Linux machine and want to inspect the filesystem footprint of an installer or configuration script before it lands, or if you need a persistent overlay directory you can hand to someone else for review. Skip it if the command you are worried about acts mainly over the network, if you are on a kernel older than 5.11, or if you need a security boundary rather than a review boundary.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 14 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem binpash/try addresses, and who hits it

Package managers, installers and setup scripts write to a system before you have any chance to look at what they wrote. The README frames the tool around that gap: it lets you run a command and inspect its effects before changing your live system. The target reader is someone with root or sudo on a Linux box who is about to run `pip3 install`, a curl-piped installer, or any script whose side effects are not obvious from reading it.

The README is explicit about the scope of the guarantee. It calls try a semisolation as opposed to a sandbox, and says it should not be used to execute commands you do not already trust on your system, because network calls are all allowed. That sentence does most of the positioning work. try is a review tool for a command you were going to run anyway, not a containment tool for a command you suspect. If your concern is exfiltration or a remote payload, try does not address it, and the authors say so rather than leaving it to inference.

It is a higher-order command in the same family as xargs, exec, nohup and find, according to the README. You prefix a command with try and the command runs normally, with its filesystem writes redirected.

How the overlay and the commit step actually work

The mechanism is two Linux features stacked: namespaces via unshare, and the overlayfs union filesystem. The command runs inside a user namespace where an overlay is mounted. Writes do not reach the real filesystem; they land in an upper directory while the real filesystem serves as the lower layer. When the command exits, try asks whether to commit.

The default flow is interactive. Running `try pip3 install libdash` runs the install and then prompts with a `Change` line, per the README example. Committing merges the upper directory back into the live system. Not committing leaves the system as it was.

Two flags break the interactive pattern. `try -n "command"` pre-executes the command and prints the overlay directory on STDOUT without committing, so you can inspect later. `try -N dir "command"` points try at an existing directory instead of a temporary one. The README shows the resulting layout: a `-N rustup-sandbox` run leaves `temproot`, `upperdir` and `workdir` inside that directory. The upper directory is where the real content sits, and the README shows `du -hs .` reporting 1.2G inside it after a rustup install.

Inspection is a first-class subcommand rather than something you do by hand. `try summary dir/` lists changed files with a `(modified/added)` marker. `try commit dir` applies them. `try explore` opens your current shell inside try, and `try explore /tmp/tmp.X6OQb5tJwr` opens an existing sandbox. The `-L` flag takes a colon-separated list of directories to merge as lower layers and implies `-n`.

Installing try and running a first command

There are three installation paths, and the README ranks them by completeness. The quickest is to download the `try` script itself, put it in your PATH, and run it. The README calls this the quick and janky way and warns you get no documentation and no utility support. The support utilities are separate binaries that the README says should help try run faster, so the script-only path is a real downgrade, not just a missing manpage.

Cloning the repository gives the full build. The README gives this sequence, run from the clone:

bash
git clone https://github.com/binpash/try.git
autoconf && ./configure && make && sudo make install

After that you should have a fully featured try, including the support utilities and the manpage. The README suggests `make test` to confirm everything works. Note the dependency list: `attr` for `getfattr`, and `pandoc` plus `autoconf` if you are working from a GitHub clone, which is exactly why the clone needs autoconf while the source distribution does not.

The third path is the source distribution from the release page. It ships the generated `configure` script and the manpage, so the build skips the generation steps:

bash
./configure && make && sudo make install

Arch and Nix users have package routes. On Arch the README points at the AUR package `try`, installable with `yay -S try` or by cloning the AUR repository and running `makepkg -sic`. On Nix the package is in nixpkgs, and the README gives `nix-shell -p try`.

A first real use, following the README example, is to run a package install under try and read the prompt before answering:

bash
try pip3 install libdash

You should see the normal pip output, then a `Change` prompt at the end. Answering it commits the install; declining leaves the system untouched. If you would rather inspect before deciding, use `try -n` and read the printed directory with `try summary`.

The kernel version and nested-mount constraints

The hard floor is Linux 5.11 or higher. The README states this plainly and ties it to a specific commit, because overlayfs in a user namespace only works from that point on. On an older kernel there is no fallback described; try simply will not work as intended.

Nested mounts are the second constraint, and it is the one most likely to bite in practice. The README says that in cases where overlayfs does not work on nested mounts you will need either mergerfs or unionfs. try should autodetect them, but you can point it at a binary explicitly with `-U`, for example `try -U ~/.local/bin/unionfs`. Autodetection that can be overridden is a reasonable design, but it means the failure mode is a detection miss rather than a clean error, and the fix requires installing a FUSE filesystem you may not have wanted.

The tested distribution list is broad but dated in places: Ubuntu 20.04 LTS or later, Debian 12, Fedora 38, Centos 9 Stream, Arch, Alpine, Rocky 9, and SteamOS 3.4.8. That list tells you the maintainers have run it on a range of package layouts, not that your specific distribution is covered. Alpine and SteamOS appearing there is a useful signal for anyone on a non-systemd or immutable base.

The test suite has its own dependencies: `bash`, `expect` and `curl`, run through `scripts/run_tests.sh`. `expect` is worth noting because it implies the tests drive interactive prompts, which matches the default commit flow.

What try does not do: network, processes, and trust

The README's own limitation is the sharpest one. Network calls are all allowed. A command that fetches a payload, phones home, or modifies a remote system does so unimpeded. The overlay only intercepts filesystem writes to the mounted tree. If your threat model involves a remote endpoint, try gives you nothing there, and the README does not pretend otherwise.

Process effects are similarly outside the picture. The description is about inspecting effects on the filesystem before modifying the live system. Nothing in the README describes cgroup limits, PID restrictions, or resource caps. A command that forks a background daemon, saturates CPU, or fills memory under try is still doing that on your machine.

There is also a disk cost that is easy to underestimate. The README's own example shows 1.2G in the upper directory after a rustup install. Because the upper directory holds every written file, a command that installs a large toolchain or downloads large artifacts consumes that space in the overlay before you decide anything. On a small root partition that is a practical failure mode, and the README does not describe a size cap or a way to bound it.

Finally, the trust boundary is stated rather than enforced. try is for commands you already trust. If you would not run the command on the machine at all, try is the wrong tool, and the README says so directly.

How try differs from containers and from filesystem snapshots

The obvious comparison is a container runtime such as Docker or Podman. The difference is in what gets shared. A container gives the process its own filesystem view built from an image, and by default its own network namespace, so you get isolation in both directions. try reuses your real filesystem as the lower layer, so the command sees your actual installed packages, your actual configuration files, and your actual home directory. That is the point: an installer that behaves correctly against your real system will behave that way under try, which is not true inside a minimal container image. The cost is that try inherits every network permission your shell has, which a container runtime does not by default.

Filesystem snapshots (LVM, btrfs, ZFS) are the other alternative, and the difference is granularity and cost. A snapshot captures the whole volume and requires the storage stack to support it, plus enough free space for the copy-on-write deltas. try captures only what the single command writes, into a directory you can inspect file by file with `try summary` and hand to someone else as a path. You do not need a snapshot-capable filesystem, and you do not roll back the whole machine to undo one install. The trade-off is that you get no protection for anything outside the mounted tree, and you cannot snapshot a system that is mid-write the way a volume snapshot can.

A third option, running the command in a throwaway VM, is strictly stronger isolation and strictly more setup. try's advantage is that it is a prefix on a command you were already typing.

Maintenance, packaging, and the MIT licence

The repository is not archived, and the last push was on 2026-08-28. The release history is uneven: v0.1.0 in June 2023, v0.2.0 in July 2023, then a long gap until the `latest` distribution tarball on 2026-08-28. The README notes a best paper and distinguished artifact award at OSDI'26, and points to the paper for a fuller description of the design and implementation. That is the strongest signal about where engineering attention has gone: the project has a published systems paper behind it, and the README defers implementation detail to it rather than duplicating it.

The practical upgrade cost depends on which install path you chose. If you installed the bare script, upgrading is replacing one file. If you built from a clone, you are re-running autoconf, configure, make and install, and you need `pandoc` and `autoconf` present each time. If you installed the source distribution, the generated configure script is already there. Arch and Nix users get upgrades through their package manager, which also means they get whatever version the packager chose, not necessarily the newest tarball.

The licence is MIT. In practical terms that permits commercial use, modification and redistribution provided the copyright notice and permission notice are preserved; the repository's `LICENSE` file is the authoritative text. This is a description of what the licence says, not legal advice, and anyone embedding try in a product should read the file and their own obligations rather than rely on a summary.

Editorial conclusion

Adopt binpash/try if you administer a Linux machine and want to inspect the filesystem footprint of an installer or configuration script before it lands, or if you need a persistent overlay directory you can hand to someone else for review. Skip it if the command you are worried about acts mainly over the network, if you are on a kernel older than 5.11, or if you need a security boundary rather than a review boundary. Before relying on it, check that overlayfs mounts correctly on your nested mounts, since the README says mergerfs or unionfs may be needed there, and confirm the version you install is the one built from the repository or the source distribution rather than the bare script, which the README describes as lacking documentation and utility support.

Frequently asked questions

Is /bin/bash necessary for binpash/try to work?

The README does not discuss /bin/bash. It lists `bash` as a dependency for running try's test suite via scripts/run_tests.sh, alongside `expect` and `curl`.

What does the #!/bin/bash line mean in this context?

The README does not cover shebang lines. What it does state is that try is a higher-order command, like xargs, exec, nohup or find, and that the quickest install is to put the `try` script in your PATH.

What is the difference between #!/bin/bash and #!/bin/sh for a tool like binpash/try?

The README does not compare these. It only names `bash` as a test-suite dependency and does not document which shell the try script itself declares.

What is the point of #!/bin/bash in a script?

The README does not explain shebang lines. For try itself, the documented entry point is the `try` script placed in your PATH or installed via `make install`, and the README describes try as a higher-order command rather than a shell script with documented header semantics.

Official sources

  1. Official README
  2. Project repository
  3. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/binpash-try.svg)](https://hysenlabs.com/projects/binpash-try)