Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 92 lines (72 sloc) 2.42 KB
#!/usr/bin/env bash
function _eachdir() {
if [[ "$1" == "-h" || "$1" == "--help" ]]; then cat <<HELP
Usage: eachdir [dirs --] commands
Run one or more commands in one or more dirs.
By default, all subdirs of the current dir will be iterated over, but if --
is specified as an arg, the dirs list will be made up of all args specified
before it. All remaining args are the command(s) to be executed for each dir.
Multiple commands must be specified as a single string argument.
In bash, aliasing like this allows you to specify aliases/functions:
alias eachdir=". eachdir"
Both of these print the working directory of every subdir of the current dir:
eachdir pwd
eachdir * -- pwd
Perform a "git pull" inside all subdirs starting with repo-:
eachdir repo-* -- git pull
Perform a few git-related commands inside all subdirs starting with repo-:
eachdir repo-* -- 'git fetch && git merge'
Copyright (c) 2012 "Cowboy" Ben Alman
Licensed under the MIT license.
return; fi
if [ ! "$1" ]; then
echo 'You must specify one or more commands to run.'
return 1
# For underlining headers.
local h1="$(tput smul)"
local h2="$(tput rmul)"
# Store any dirs passed before -- in an array.
local dashes d
local dirs=()
for d in "$@"; do
if [[ "$d" == "--" ]]; then
shift $(( ${#dirs[@]} + 1 ))
dirs=("${dirs[@]}" "$d")
# If -- wasn't specified, default to all subdirs of the current dir.
[[ "$dashes" ]] || dirs=(*/)
local nops=()
# Do stuff for each specified dir, in each dir. Non-dirs are ignored.
for d in "${dirs[@]}"; do
# Skip non-dirs.
[[ ! -d "$d" ]] && continue
# If the dir isn't /, strip the trailing /.
[[ "$d" != "/" ]] && d="${d%/}"
# Execute the command, grabbing all stdout and stderr.
output="$( (cd "$d"; eval "$@") 2>&1 )"
if [[ "$output" ]]; then
# If the command had output, display a header and that output.
echo -e "${h1}${d}${h2}\n$output\n"
# Otherwise push it onto an array for later display.
nops=("${nops[@]}" "$d")
# List any dirs that had no output.
if [[ ${#nops[@]} > 0 ]]; then
echo "${h1}no output from${h2}"
for d in "${nops[@]}"; do echo "$d"; done
# By putting the above code inside a function, if this file is sourced (which
# is required for external aliases/functions to be used as commands), vars
# can be local and return can be used to exit.
_eachdir "$@"