patternbashMinor
Bash script to run development tasks for configured projects
Viewed 0 times
scriptprojectstasksdevelopmentforconfiguredbashrun
Problem
I wrote this script template at work to save typing repetitive commands and to improve my Bash-fu. I'd like to know of any moderate-to-severe quoting, robustness, security or usability issue. All code provided in answers should work in Bash 4.
.sedevrc:
```
#!/bin/bash
se_projects=()
se_cvs_dir="${USER}@172.0.0.1/export/home/cvsrootdir"
#============PROJECT CONFIG START================#
declare -A product
product[CVSROOT]="${se_cvs_dir}/product"
product[SOURCEDIR]="${HOME}/product"
product[WORKDIR]="${HOME}/test"
product[MAINPRG]="${product[SOURCEDIR]}/build/product"
se_projects+=("${!product@}")
#================================================#
# Other products in the same format as above
#=============PROJECT CONFIG END=================#
# se user commands
function secvs
{
se_loop_projects "_se_cvs" "$@"
}
function sectags
{
se_loop_projects "_se_ctags" "$@"
}
function semake
{
se_loop_projects "_se_make" "$@"
}
function sealias
{
se_loop_projects "_se_alias" "$@"
}
# se helper functions
function _se_cvs
{
echo_info "Updating ${project}..."
local cvsroot=${project}[CVSROOT]
CVSROOT=:pserver:${!cvsroot:?}
local sourcedir=${project}[SOURCEDIR]
cd ${!sourcedir:?}
cvs -q update -Pd && echo_noerror "Update ${project} complete" || echo_error "Update ${project} failed"
}
function _se_ctags
{
echo_info "Tagging ${project}..."
local sourcedir=${project}[SOURCEDIR]
cd ${!sourcedir:?}/src
{ file tags | grep 'Ctags tag' >/dev/null; } || rm -f tags
ctags -R --exclude=obj && echo_noerror "Tag ${project} complete" || echo_error "Tag ${project} failed"
}
function _se_make
{
echo_info "Building ${project}..."
local sourcedir=${project}[SOURCEDIR]
cd ${!sourcedir:?}
if [[ -d build ]] && (( $(bc 60 60 24 * 5 ))
then
make clean || echo_error "Clean ${project} failed"
fi
make && echo_noerror "Build ${project} complete" || echo_error "Build ${project} failed"
}
function _se_a
.sedevrc:
```
#!/bin/bash
se_projects=()
se_cvs_dir="${USER}@172.0.0.1/export/home/cvsrootdir"
#============PROJECT CONFIG START================#
declare -A product
product[CVSROOT]="${se_cvs_dir}/product"
product[SOURCEDIR]="${HOME}/product"
product[WORKDIR]="${HOME}/test"
product[MAINPRG]="${product[SOURCEDIR]}/build/product"
se_projects+=("${!product@}")
#================================================#
# Other products in the same format as above
#=============PROJECT CONFIG END=================#
# se user commands
function secvs
{
se_loop_projects "_se_cvs" "$@"
}
function sectags
{
se_loop_projects "_se_ctags" "$@"
}
function semake
{
se_loop_projects "_se_make" "$@"
}
function sealias
{
se_loop_projects "_se_alias" "$@"
}
# se helper functions
function _se_cvs
{
echo_info "Updating ${project}..."
local cvsroot=${project}[CVSROOT]
CVSROOT=:pserver:${!cvsroot:?}
local sourcedir=${project}[SOURCEDIR]
cd ${!sourcedir:?}
cvs -q update -Pd && echo_noerror "Update ${project} complete" || echo_error "Update ${project} failed"
}
function _se_ctags
{
echo_info "Tagging ${project}..."
local sourcedir=${project}[SOURCEDIR]
cd ${!sourcedir:?}/src
{ file tags | grep 'Ctags tag' >/dev/null; } || rm -f tags
ctags -R --exclude=obj && echo_noerror "Tag ${project} complete" || echo_error "Tag ${project} failed"
}
function _se_make
{
echo_info "Building ${project}..."
local sourcedir=${project}[SOURCEDIR]
cd ${!sourcedir:?}
if [[ -d build ]] && (( $(bc 60 60 24 * 5 ))
then
make clean || echo_error "Clean ${project} failed"
fi
make && echo_noerror "Build ${project} complete" || echo_error "Build ${project} failed"
}
function _se_a
Solution
I see some things that may help you improve your code.
Use the correct form for associative arrays
The code contains this line:
But I am pretty sure that what was meant was this:
Quote to prevent word splitting
This line needs quotes to prevent word splitting:
If the contents of
The same issue exists for the last clause of the
Use
If the
Use
One of the lines in the current code is this:
The intent appears to be to print one string or the other depending on the outcome of the
Or as I'd probably prefer formatting it:
Understand the use of numeric variables
In this context:
The
Don't mix string and array
In this line
The colors expand to strings, but the
There's more, but it's all I have time for at the moment.
Use the correct form for associative arrays
The code contains this line:
local cvsroot=${project}[CVSROOT]But I am pretty sure that what was meant was this:
local cvsroot=${project[CVSROOT]}Quote to prevent word splitting
This line needs quotes to prevent word splitting:
cd ${!sourcedir:?}If the contents of
sourcedir contains a path with an embedded space, the cd will fail. Add quotes to prevent this problem:cd "${!sourcedir:?}"The same issue exists for the last clause of the
complete function.Use
|| exit if a command failsIf the
cd command mentioned above actually fails, the script will proceed anyway and this is unlikely to be desired. Instead, you could use this:cd "${!sourcedir:?}" || exit 1Use
if-else if you need that functionalityOne of the lines in the current code is this:
ctags -R --exclude=obj && echo_noerror "Tag ${project} complete" || echo_error "Tag ${project} failed"The intent appears to be to print one string or the other depending on the outcome of the
ctags program. However, be aware that the second message might be printed even if ctags runs without error. This is because echo_noerror might fail and then the echo_error function would be invoked. To make the code more robust, don't use this trick. Instead, use the plain old if-else construct:if ctags -R --exclude=obj; then echo_noerror "Tag ${project} complete"; else echo_error "Tag ${project} failed"; fiOr as I'd probably prefer formatting it:
if ctags -R --exclude=obj
then
echo_noerror "Tag ${project} complete"
else
echo_error "Tag ${project} failed"
fiUnderstand the use of numeric variables
In this context:
for (( i=0; i<${project_count}; i++ ))The
${} is not needed because it's a numeric variable. Instead, just write this:for (( i=0; i<project_count; i++ ))Don't mix string and array
In this line
echo "${echo_noerror_color}$@${echo_reset_color}"The colors expand to strings, but the
$@ is an array. To make it a string, use this instead:echo "${echo_noerror_color}$*${echo_reset_color}"There's more, but it's all I have time for at the moment.
Code Snippets
local cvsroot=${project}[CVSROOT]local cvsroot=${project[CVSROOT]}cd ${!sourcedir:?}cd "${!sourcedir:?}"cd "${!sourcedir:?}" || exit 1Context
StackExchange Code Review Q#150292, answer score: 2
Revisions (0)
No revisions yet.