Bash Notes
shopt
If you set shopt
in a function, reset to its default state with trap
:
func() {
trap "$(shopt -p globstar)" RETURN
shopt -q -s globstar
}
find, grep, print0, -0, -z
Don’t use find
in for
loops, because filenames can contain spaces.
Try to use globstar
and nullglob
or null byte terminated strings.
Instead of:
func() {
for file in $(find /usr/lib* -type f -name 'lib*.a' -print0 ); do
echo $file
done
}
use:
func() {
trap "$(shopt -p nullglob globstar)" RETURN
shopt -q -s nullglob globstar
for file in /usr/lib*/**/lib*.a; do
[[ -f $file ]] || continue
echo "$file"
done
}
Or collect the filenames in an array, if you need them more than once:
func() {
trap "$(shopt -p globstar)" RETURN
shopt -q -s globstar
filenames=( /usr/lib*/**/lib*.a )
for file in "${filenames[@]}"; do
[[ -f $file ]] || continue
echo "$file"
done
}
Or, if you really want to use find
, use -print0
and an array:
func() {
mapfile -t -d '' filenames < <(find /usr/lib* -type f -name 'lib*.a' -print0)
for file in "${filenames[@]}"; do
echo "$file"
done
}
-d '' is the same as -d $'\0' and sets the null byte as the delimiter.
|
or:
func() {
find /usr/lib* -type f -name 'lib*.a' -print0 | while read -r -d '' file; do
echo "$file"
done
}
or
func() {
while read -r -d '' file; do
echo "$file"
done < <(find /usr/lib* -type f -name 'lib*.a' -print0)
}
Use the tool options for null terminated strings, like -print0
, -0
, -z
, etc.