Bash script for cleaning Visual Studio Project build directories (e.g.: bin/, obj/, etc.) from a particular path, recursively.
#!/usr/bin/env bash
#
# Delete dotnet build dirs and files (e.g. 'bin', 'obj', etc...)
# recursively, starting from the current working directory (PWD).
#
# TODO:
# - Handle unknown options passed in as arguments
#
# Author: Jon LaBelle
# Snippet: https://jonlabelle.com/snippets/view/shell/clean-visual-studio-project-build-files-sh
# Gist: https://gist.github.com/jonlabelle/41e67b8b1eac69aab0e5d2e419859dce
# Updated: February 3, 2021
#
set -e
set -o pipefail
readonly SCRIPT_NAME=$(basename "${0}")
IS_DRYRUN=true
# hat tip: https://github.com/lhunath/scripts/blob/master/bashlib/bashcomplib#L98
show_args() {
echo
local i=0
for arg; do
printf "arg %d: %s\n" "$((i++))" "$arg"
done
i=0
for word in "${COMP_WORDS[@]}"; do
printf "word %d: %s -> %s %s\n" "$i" "$word" "$(xargs <<< "$word")" "$( ((i == "$COMP_CWORD")) && echo '<CWORD>')"
((i++))
done
}
die() {
printf >&2 '%s\n' "$*"
exit 1
}
show_usage() {
echo "Usage: ${SCRIPT_NAME} [option]"
echo
echo "Delete dotnet build dirs and files (e.g. 'bin', 'obj', etc...)"
echo "recursively, starting from the current working directory (PWD)."
echo
echo "Options:"
echo
echo " -k, --kill-dotnet-procs killall(1) dotnet processes"
echo " -n, --dry-run preview without delete."
echo " -h, --help show this help message and exit."
echo ""
echo "Note: Only one option is allowed per execution."
echo
}
heading() { printf '→ %s\n' "$@"; }
warn() { printf "$(tput setaf 3)%s$(tput sgr0)\\n" "$@"; }
success() { printf "$(tput setaf 76)✔ %s$(tput sgr0)\\n" "$@"; }
function killall_dotnet_processes() {
heading "Killing any running dotnet processes..."
# temporarily allow failures from killall(1)
set +e
killall dotnet
set -e
}
clean_dirs_recursively() {
heading "Cleaning '${1}' dirs..."
find . -name "${1}" -type d -print | xargs -0 echo
if [ "$IS_DRYRUN" = "false" ]; then
# shellcheck disable=SC2086,SC2048
find . -name ${1} -type d -print0 | xargs -0 rm -rf
fi
}
clean_files_recursively() {
heading "Cleaning '${1}' files..."
find . -name "${1}" -type f -print | xargs -0 echo
if [ "$IS_DRYRUN" = "false" ]; then
# shellcheck disable=SC2086,SC2048
find . -name ${1} -type f -print0 | xargs -0 rm -rf
fi
}
main() {
echo
if [[ $# -gt 1 ]]; then
local shown_args
# shellcheck disable=SC2086,SC2048
shown_args="$(show_args $*)"
warn "Multiple options in not supported."
echo "${shown_args}"
echo ""
die "See --help for usage."
fi
if [[ $1 == "-h" || $1 == "--help" || $1 == "help" || $1 == "-v" || $1 == "--version" ]]; then
show_usage
exit 0
fi
if [[ $1 == "-n" || $1 == "--dry-run" ]]; then
IS_DRYRUN=true
warn "Dry-run only... files will NOT be deleted."
echo
else
IS_DRYRUN=false
fi
if [[ $1 == "-k" || $1 == "--kill-dotnet-procs" ]]; then
killall_dotnet_processes
fi
#
# clean vs dirs:
clean_dirs_recursively 'bin'
clean_dirs_recursively 'obj'
# other dotnet ide user setttings dirs (visual studio, ryder, vscode)
# clean_dirs_recursively '.vs'
# clean_dirs_recursively '.idea'
# clean_dirs_recursively '.vscode'
# careful with this one... pass '--dry-run' to preview without delete
clean_dirs_recursively 'packages'
# node_modules
clean_dirs_recursively 'node_modules'
# test results
clean_dirs_recursively 'test-results'
clean_dirs_recursively 'TestResults'
clean_dirs_recursively 'coverlet'
# published output
clean_dirs_recursively 'publish'
clean_dirs_recursively 'artifacts'
#
# legacy visual studio user settings files:
clean_files_recursively '*.suo'
#
# vs and mono-develop user prefs
clean_files_recursively '*.user'
clean_files_recursively '*.userprefs'
#
# stylecop cache files:
clean_files_recursively 'StyleCop.Cache'
#
# macOS files:
clean_files_recursively '.DS_Store'
echo
success "Finished."
echo
exit 0
}
# shellcheck disable=SC2086,SC2048
main $*