Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 341 lines (290 sloc) 7.27 KB
#!/bin/bash
# ----------------------------------------------------------------------
# libfind
#
# Finds library files with the use of expressions.
#
# By default, it searches for files in directories specified in
# /etc/ld.so.conf, but it can be configured to use other directories
# instead.
#
# Usage: libfind[.bash] [options] [-e] expression [[--] expression ...]
#
# Author: konsolebox
# Copyright Free / Public Domain
# May 27, 2018
# ----------------------------------------------------------------------
VERSION='2018-05-27'
[[ $BASH_VERSINFO -ge 4 ]] || {
echo "This script requires Bash version 4.0 or newer." >&2
exit 1
}
shopt -s extglob
shopt -so noglob
declare -A LD_CONF_HASH=()
declare -a LIB_PATHS=()
declare -a LIB_PATHS_COMMON=(
/usr/x86_64-pc-linux-gnu/lib64
/usr/x86_64-pc-linux-gnu/lib32
/usr/x86_64-pc-linux-gnu/libx32
/usr/x86_64-pc-linux-gnu/lib
/usr/i386-pc-linux-gnu/lib32
/usr/i386-pc-linux-gnu/lib
/usr/local/lib64
/usr/local/lib32
/usr/local/libx32
/usr/local/lib
/lib64
/lib32
/libx32
/lib
/usr/lib64
/usr/lib32
/usr/libx32
/usr/lib
)
function show_help_info {
echo "Finds library files based on expressions.
By default it searches for files in directories specified in
/etc/ld.so.conf but it can be configured to use other directories
instead.
Usage: $0 [options] [-e] expression [[--] expression ...]
Use of common paths:
-c Search in common library directories instead of those
specified in /etc/ld.so.conf.
-C Same as -c but adds the common library directories
into the list extracted from /etc/ld.so.conf.
Glob-based Types:
-p, --path Treat all expressions as keywords that would match
against the whole path and not just the filename.
-x, --exact Treat all expressions as exact glob patterns. No
extra wildcard character is added before or after
the keyword.
-X, --exact-path Same as -x, but the glob pattern applies with the
whole path, and not just the filename.
Regex-based Types:
--awk Treat all expressions as Awk regular expressions.
--egrep Treat all expressions as egrep expressions.
--emacs Treat all expressions as Emacs regular expressions.
-E, --extended Treat all expressions as extended regular expressions.
-r, --regex Treat all expressions as basic regular expressions.
Modifiers:
-s Treat all expressions as case sensitive. This option
can co-exist with other expression type options.
Others:
-e Imply that the following argument is an expression.
-h, --help Show this help info.
-V, --version Show version.
Notes:
Only one of --awk, --egrep, --emacs, -E, -r, -p, -x and -X can become
effective, and it would affect all expressions including the ones specified
before them.
Regex-based expression types rely on find's -regex so they match a whole
pathname and not just a file's filename.
When no expression type is specified, it defaults to glob patterns." >&2
}
function get_clean_path {
local t=() i=0 IFS=/
case $1 in
/*)
set -- $1
;;
*)
set -- $PWD $1
;;
esac
for __; do
case $__ in
..)
(( i )) && unset 't[--i]'
continue
;;
''|.)
continue
;;
esac
t[i++]=$__
done
__="/${t[*]}"
}
function get_lib_paths {
# This function tries to comply with ldconfig's behavior.
# See parse_conf() and parse_conf_include() in ldconfig.c.
# It expects that IFS is set to default value, and that noglob is set.
local file=$1
if [[ -z ${LD_CONF_HASH[$file]} && -f $file && -r $file ]]; then
LD_CONF_HASH[$file]=.
while read -r __; do
case $__ in
/*)
get_clean_path "$__"
LIB_PATHS+=("$__")
;;
include\ *)
set -- $__
shift
for __; do
if [[ $__ == /* ]]; then
get_clean_path "$__"
else
get_clean_path "$file/../$__"
fi
while read -r __; do
get_lib_paths "$__"
done < <(compgen -G "$__")
done
;;
esac
done < "$file"
fi
}
function fail {
printf '%s\n' "$@" >&2
exit 1
}
function main {
local case_sensitive=false expressions=() mode=default use_or_add_common_paths=false __
while [[ $# -gt 0 ]]; do
case $1 in
-c)
[[ $use_or_add_common_paths == add ]] && fail "You can only specify one of -c and -C."
use_or_add_common_paths=use
;;
-C)
[[ $use_or_add_common_paths == use ]] && fail "You can only specify one of -c and -C."
use_or_add_common_paths=add
;;
--awk|--egrep|--emacs)
mode=${1#--}
;;
-E|--extended)
mode=extended
;;
-p|--path)
mode=path
;;
-r|--regex)
mode=basic
;;
-x|--exact)
mode=exact_pattern
;;
-X)
mode=exact_path_pattern
;;
-s)
case_sensitive=true
;;
-e)
shift
[[ $# -eq 0 ]] && error "No argument follows -e."
expressions+=("$1")
;;
-h|--help)
show_help_info
exit 1
;;
-V|--version)
echo "$VERSION" >&2
exit 1
;;
--)
expressions+=("${@:2}")
break
;;
-*)
fail "Invalid option: $1"
;;
*)
expressions+=("$1")
;;
esac
shift
done
[[ ${#expressions[@]} -eq 0 ]] && fail "No expression was specified. Run with --help to get usage info."
if [[ $mode == @(default|exact_pattern) ]]; then
for __ in "${expressions[@]}"; do
if [[ $__ == */* ]]; then
fail "You can't include a forward-slash character (/) when matching against a filename." \
"Please run libfind with --help to see other search methods."
fi
done
fi
if [[ $use_or_add_common_paths == use ]]; then
LIB_PATHS=("${LIB_PATHS_COMMON[@]}")
else
get_lib_paths /etc/ld.so.conf
if [[ $use_or_add_common_paths == add ]]; then
LIB_PATHS+=("${LIB_PATHS_COMMON[@]}")
fi
fi
local lib_paths_filtered=()
local -A hash=()
for __ in "${LIB_PATHS[@]}"; do
if [[ $__ != *([[:blank:]]) && -z ${hash[$__]} && -d $__ && -r $__ && -x $__ ]]; then
lib_paths_filtered+=("$__")
hash[$__]=.
fi
done
[[ ${#lib_paths_filtered[@]} -eq 0 ]] && return 1
local name_opt='-iname' path_opt='-ipath' regex_opt='-iregex'
if [[ $case_sensitive == true ]]; then
name_opt='-name'
regex_opt='-regex'
path_opt='-path'
fi
local expr_opt=$name_opt regex_type_args=() add_wildcards=true
case $mode in
awk)
expr_opt=$regex_opt
regex_type_args=(-regextype posix-awk)
add_wildcards=false
;;
basic)
expr_opt=$regex_opt
regex_type_args=(-regextype posix-basic)
add_wildcards=false
;;
emacs)
expr_opt=$regex_opt
regex_type_args=(-regextype emacs)
add_wildcards=false
;;
egrep)
expr_opt=$regex_opt
regex_type_args=(-regextype posix-egrep)
add_wildcards=false
;;
extended)
expr_opt=$regex_opt
regex_type_args=(-regextype posix-extended)
add_wildcards=false
;;
exact_pattern)
expr_opt=$name_opt
regex_type_args=()
add_wildcards=false
;;
exact_path_pattern)
expr_opt=$path_opt
regex_type_args=()
add_wildcards=false
;;
path)
expr_opt=$path_opt
regex_type_args=()
;;
esac
local expr_args=()
if [[ $add_wildcards == true ]]; then
for __ in "${expressions[@]}"; do
expr_args+=("$expr_opt" "*$__*")
done
else
for __ in "${expressions[@]}"; do
expr_args+=("$expr_opt" "$__")
done
fi
find "${lib_paths_filtered[@]}" -maxdepth 1 -xtype f "${regex_type_args[@]}" "${expr_args[@]}"
}
main "$@"