Reputation: 15270
I have lots of log files in a deeper directory like so:
/my/deep/path/to/log/files/
foo-2016-10-10.log
foo-2016-10-11.log
bar-2016-10-10.log
bar-2016-10-11.log
Many times a day I find myself tailing different logs like so:
tail -fn 100 /my/deep/path/to/log/files/foo-2016-10-10.log
Is it possible to alias everything but the final file? And allow tab completion to get me the rest of the way?
For example, I'd love to type tl
(short for tail log) and the specific log file I'm looking for like so:
$ tl foo
[HIT TAB KEY]
$ tl foo-2016-10-1
[HIT 1 and TAB KEY]
$ tl foo-2016-10-11.log
Is this possible in bash? How can I accomplish this?
Upvotes: 2
Views: 468
Reputation: 46853
Pretty much a clone of Charles Duffy's answer (with the only difference that he uses globs and I'm using compgen
— which is probably the way completions are (badly) designed to be written):
_tl_COMPDIR=/my/deep/path/to/log/files/
_comp_tl() {
local IFS=$'\n'
COMPREPLY=( $(compgen -f -- "$_tl_COMPDIR$2") )
COMPREPLY=( "${COMPREPLY[@]#"$_tl_COMPDIR"}" )
}
tl() (
cd -- "$_tl_COMPDIR" && tail -fn 100 "$@"
)
complete -o nospace -o filenames -F _comp_tl tl
Upvotes: 3
Reputation: 295619
It's a bit ugly, but this does the job:
_tl_log_path=/my/deep/path/to/log/files
_tl_completions() {
COMPREPLY=( "${_tl_log_path}/$2"* )
COMPREPLY=( "${COMPREPLY[@]#${_tl_log_path}/}" )
if [[ ${COMPREPLY[0]} = "$2*" ]]; then
COMPREPLY=( )
fi
}
complete -F _tl_completions -o filenames tl
As for your tl
, I'd suggest implementing it as such:
tl() {
# generate an array of arguments to pass to tail
local -a args=( )
# iterate over each argument given to the function
for arg; do
if [[ -e "$_tl_log_path/$arg" ]]; then
# if a like-name file exists under _tl_log_path, add that filename as an argument
args+=( "$_tl_log_path/$arg" )
else
# otherwise, add that argument exactly as it already exists
args+=( "$arg" )
fi
done
# ...and, finally, execute the tail command.
tail -f "${args[@]}"
}
...though you could also go cheap and easy:
tl() (
cd "$_tl_log_path" || exit
exec tail -f "$@"
)
To explain:
complete -F funcname cmdname
indicates that the shell function funcname
should be called to determine how to complete the command cmdname
. -o filenames
further indicates that the results should be treated as filenames.COMPREPLY
is a shell array which the completion function is expected to fill out with possible completions.COMPREPLY=( "${_tl_log_path}/$2"* )
expands the given content as a glob (because the *
is, intentionally, outside the quotes).COMPREPLY=( "${COMPREPLY[@]#${_tl_log_path}/" )
then strips the log directory as a prefix from each result in the array.[[ ${COMPREPLY[0]} = "$2*" ]]
(with the asterisk inside the quotes, on this occasion), detects the case where no possible glob expansion results existed, and where (thus) the glob expanded to itself (assuming that the shell's configuration via shopt
is at defaults).Upvotes: 2
Reputation: 204
Yes you can simply switch to that directory before executing the command.
$ cd /my/deep/path/to/log/files/
$ tl <tab>
Upvotes: 0