Fosh: Execute shell commands in multiple directories grouped by tags
Tags: showdev, productivity, terminal, git
Published: 2019-04-16 19:35:40

---
title: Fosh: Execute shell commands in multiple directories grouped by tags
published: true
description: Fosh: Execute shell commands in multiple directories grouped by tags
tags: showdev,productivity,terminal,git
---

For developers who **running the same command in different directories** repeatedly, Fosh is a productivity tool that saves time by **executing the command without having to change the directory**. Unlike other similar tools, Fosh does not bound to a certain software (like Git for example), it can **execute any shell command**. **It works at least on Windows and Linux**.

**If you prefer Bash, have a look at https://github.com/bimlas/bash-mosh/**

* **Manage multiple Git repositors together**
  * Checkout the same branch for project and its submodules
  * Commit with the same message: walk through the repos without interruption and copy / paste the same commit message
  * Prevent early push: you do not have to remember which repositories have modified, just look at them at the end of the day to see where you need to push
* **Control multiple vagrant machines at the same time**

The essence of the code in a nutshell:

```
for(dir in selectedDirectories) {
  cd(dir);
  shellCommand();
}
```

This also means the name: `for ... shell ...` -> `fosh`.

## Installation

```
$ npm install -g fosh
```

Get the source code, report bugs, open pull requests, or just star because you didn't know that you need it:

* https://gitlab.com/bimlas/node-fosh (official repository)
* https://github.com/bimlas/node-fosh (mirror, star if you like it)

## Commands

### Tag: Assign tags to directories

The tags can be specified as command-line parameters prefixed with `@`, directories should be listed in the prompt, or piped to stdin.

```
$ fosh tag "@pictures" "@personal"
fosh: tag > /home/myself/photos
fosh: tag > /home/mom/my_little_family

$ echo -e "/home/myself/photos \n /home/mom/my_little_family" | fosh tag "@pictures" "@personal"
```

#### Find Git repositories

**Tagging Git repositories** under the current directory (`./`) with
"git-repos" tag:

```
# Linux / Windows Git Bash / ...
$ find "./" -name ".git" -printf "%h\n" | fosh tag "@git-repos"

# Windows PowerShell
$ Get-ChildItem './' -Recurse -Directory -Hidden -Filter '.git' | ForEach-Object { Split-Path $_.FullName -Parent } | fosh tag '@git-repos'
```

**On Windows you can use Everything search engine's `es` [command-line interface](https://www.voidtools.com/support/everything/command_line_interface/) to find Git repositories rapidly**. Use the following command in PowerShell for this (omit the path of the root directory (`./src`) to find everywhere):

```
$ es -regex '^\.git$' './src' | Split-Path -Parent | fosh tag '@git-repos'
```

### List: Prints the path of the tag list file

You can edit it in a texteditor (Notepad, Vim, etc.).

### Run: Execute commands in multiple directories

Arguments can be tags and paths.

```
$ fosh run "@git-repos" "../wip-project"
fosh: run > git status --short --branch

__ @1 awesome-project (/home/me/src/) ________________________________________
## master
AM README.md
 M package.json

__ @2 git-test (/home/me/src/) _______________________________________________
## master...origin/master
 M README.adoc
 M encoding/cp1250-encoding-dos-eol.txt
 M encoding/dos-eol.txt

__ @3 wip-project (/home/me/helping-tom/) ____________________________________
## master...origin/master
 M example-code.js

==============================================================================
fosh: run > another command and so on ...
```

#### Filtering the directory list

If you want to **execute a command only in certain directories**, you can select them by their index.

```
fosh: run > @1,3 git status --short --branch

__ @1 awesome-project (/home/me/src/) ________________________________________
## master
AM README.md
 M package.json

__ @3 wip-project (/home/me/helping-tom/) ____________________________________
## master...origin/master
 M example-code.js
```

#### Execute in the most recently used directories

**This is useful if the output is long** and you want to execute additional commands on certain directories. In this case, open a new terminal window (so you can look back at results in the current terminal) and run the program without arguments: the directory list is always stored when tag or directory arguments are given, but if you run it without arguments, it executes the commands on the last specified directories.

```
$ fosh run "@git-repos" "../wip-project"
fosh: run > git status --short --branch

__ @1 awesome-project (/home/me/src/) ________________________________________
## master
AM README.md
...

# Another terminal

$ fosh run
fosh: WARNING: Using most recently used directory list
fosh: run > @3 git diff

__ @3 wip-project (/home/me/helping-tom/) ____________________________________
 example-code.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/example-code.js b/example-code.js
index 12b5e40..733220f 100644
--- a/example-code.js
+++ b/example-code.js
...
```