是否可以在bash中添加允许制表完成的别名?

时间:2016-09-28 15:16:03

标签: bash shell command-line

我在更深的目录中有很多日志文件,如下所示:

/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

我一天多次发现自己拖着不同的日志:

tail -fn 100 /my/deep/path/to/log/files/foo-2016-10-10.log

除了最终文件之外,是否可以别名? 允许标签完成让我完成其余的工作?

例如,我想输入tl(尾部日志的简称)和我正在寻找的特定日志文件:

$ tl foo
      [HIT TAB KEY]
$ tl foo-2016-10-1
      [HIT 1 and TAB KEY]
$ tl foo-2016-10-11.log

bash有可能吗?我怎么能做到这一点?

3 个答案:

答案 0 :(得分:3)

几乎是Charles Duffy答案的克隆(唯一的区别是他使用了globs并且我使用compgen - 这可能是完成(非常)设计的方式写的):

_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

答案 1 :(得分:2)

这有点难看,但是这样做了:

_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

至于你的tl,我建议你这样做:

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[@]}"
}

...虽然你也可以便宜又轻松:

tl() (
  cd "$_tl_log_path" || exit
  exec tail -f "$@"
)

解释:

  • complete -F funcname cmdname表示应调用shell函数funcname以确定如何完成命令cmdname-o filenames进一步表明结果应被视为文件名。
  • COMPREPLY是一个shell数组,预计完成函数将填写可能的完成。
  • COMPREPLY=( "${_tl_log_path}/$2"* )将给定内容扩展为glob(因为*有意地在引号之外)。
  • COMPREPLY=( "${COMPREPLY[@]#${_tl_log_path}/" )然后将日志目录作为数组中每个结果的前缀。
  • 检查[[ ${COMPREPLY[0]} = "$2*" ]](在这种情况下,星号里面引号)是否检测到不存在可能的全局扩展结果的情况,以及(因此)glob扩展到的位置本身(假设shell的shopt配置是默认值)。

答案 2 :(得分:0)

是的,你可以在执行命令之前直接切换到该目录。

$ cd /my/deep/path/to/log/files/
$ tl <tab>