7 releases

0.3.1 Jun 10, 2024
0.3.0 Jun 10, 2024
0.2.3 Jun 7, 2024
0.1.0 Jun 5, 2024

#2666 in Command line utilities

Custom license

27KB
386 lines

withd

withd is a simple command-line tool that allows you to run a command with a different working directory without affecting the current shell's working directory.

Why is this useful?

Many commands – such as git, npm, and cargo – require you to run them from a specific directory. This can be done by cding into the directory:

cd /path/to/repo
git status
cd -

or by using a subshell to isolate the change:

( cd /path/to/repo && git status )

The first is cumbersome. The latter can be confusing when also trying to work with shell variables in a script, for example, since the subshell cannot propagate changes to the parent shell. It's also easy to forget.

Then there's CDPATH. If this is set in your shell, cd's behaviour changes and you might end up in a different directory than you expected. I've seen this be a source of confusion – and a disruptive and very difficult to diagnose bug.

withd does not have these problems. It's simple and predictable.

withd --help

$ withd --help
Run a command in another directory.

Usage: withd [OPTIONS] <DIRECTORY> [COMMAND]...

Arguments:
  <DIRECTORY>
          The directory in which to execute the command.

  [COMMAND]...
          The command and its arguments.

          [env: SHELL=/opt/homebrew/bin/bash]

Options:
  -c, --create
          Create the directory if it does not exist.

  -t, --temporary
          Create a temporary directory within DIRECTORY. This temporary
          directory will be deleted when the command completes. Note that this
          option modifies slightly how the DIRECTORY argument is used. For
          example:

          - `withd -tc foo/bar.XXXX.baz …` will create the directory `foo` (and
          will not remove it later on) and a temporary directory inside it
          called `bar.1234.baz` (where the 1234 is random).

          - `withd -tc foo …` will create `foo`, as above, and a temporary
          directory inside it named `.tmp123456` (again, where 123456 is
          random).

          - `withd -t foo …` will create a temporary directory named
          `.tmp123456` (again, where 123456 is random) in `foo`, but assumes
          that `foo` already exists.

          - `withd -t foo.XXXX.bar …` will create a temporary directory named
          `foo.1234.bar` in the system's temporary directory, e.g. $TMPDIR.

          - `withd -t "" …` will create a temporary directory named `.tmp123456`
          in the system's temporary directory, e.g. $TMPDIR.

  -h, --help
          Print help (see a summary with '-h')

  -V, --version
          Print version

The executed command can use the `WHENCE` environment variable to refer back to
the directory from whence `withd` was invoked.

Installation

For now, use Cargo:

cargo install withd

Usage

withd /path/to/repo git status

To create the directory:

withd -c /some/where echo "Hello, world!"

(-c is short for --create.)

Making a release

  1. Regenerate shell completions: cargo completions.
  2. Bump version in Cargo.toml.
  3. Paste updated --help output into README.md (this file; see near the top). On macOS the command cargo withd --help | pbcopy is helpful. Note that --help output is not the same as -h output: it's more verbose and that's actually what we want here.
  4. Build and test. The latter on its own does do a build, but a test build can hide warnings about dead code, so do both.
    • With default features: cargo build && cargo test
    • Without: cargo build --no-default-features && cargo test --no-default-features
  5. Commit with message "Bump version to $VERSION."
  6. Tag with "v$VERSION", e.g. git tag v1.0.10.
  7. Push: git push && git push --tags.
  8. Publish: cargo publish.

License

GNU General Public License 3.0 (or later). See LICENSE.

Dependencies

~7–17MB
~246K SLoC