使用变量隐藏的根前缀完成Tcsh和/或bash目录

前端之家收集整理的这篇文章主要介绍了使用变量隐藏的根前缀完成Tcsh和/或bash目录前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在尝试在tcsh和/或bash中设置目录完成(两者都在我的网站上使用)稍微扭曲:对于特定命令“foo”,我想完成使用自定义函数来匹配first / -deimited term到实际子树节点,然后按照正常目录完成任何连续的术语.它是cdpath和completion的组合,或者我想是一种目录完成形式,其中起始点由完成脚本控制.它的工作原理如下:
$foo xxx<TAB>
(custom completion function produces choices it finds at arbitrary levels in the dir tree)
xxxYYY xxxZZZ xxxBLAH ...
foo xxxYYY/<TAB>
(normal directory completion proceeds from this point on,to produce something like:)
foo scene/shot/element/workspace/user/...

我们想这样做是因为我们有一个大型的生产开发树(这是一个CGI生产设施),精通外壳的用户一直在导航和跳跃.抱怨是树的上层是繁琐和多余的;他们只需要在第一个学期快速搜索,找到可能的“头部”选择并从那里完成目录.似乎可编程完成可以提供一种方法来实现这一点,但它变得相当难以捉摸.

我做了几次自定义bash和tcsh完成的尝试,但是我得到的最接近的是一种“单词完成”形式,用户必须将目录级别视为带空格的单独单词(例如foo scene / shot) / element / workspace / …).我可以继续攻击我目前的脚本 – 但我一直想知道是否有一些我不理解的东西 – 这是我第一次尝试完成程序,而且这些文档和示例在shell书籍和互联网上相当薄弱.如果有任何完成大师可以让我走上正轨,我会很感激.

FWIW:这是我到目前为止所做的事情(首先是tcsh,然后是bash).请注意,静态根“/ root / sub1 / sub2 / sub3”只是搜索功能的占位符,可以在不同级别找到不同的匹配项.如果我可以让它工作,我可以稍后在搜索功能中.同样,两个示例都执行单词完成,这要求用户在每个匹配的术语后键入一个空格(我还必须删除函数中的空格以构造实际路径,然后!)

TCSH示例(注意该函数实际上是一个bash脚本):

complete complete_p2 'C@*@`./complete.p2.list.bash $:1 $:2 $:3 $:4 $:5 $:6 $:7 $:8 $:9`@@'

#!/bin/bash --norc

# complete.p2.list.bash - Completion prototype "p2" for shotc command

# Remove spaces from input arguments
ppath=`echo $@ | sed -e 's/ //g'`

# Print basenames (with trailing slashes) of matching dirs for completion
ls -1 -d /root/sub1/sub2/sub3/$ppath* 2>/dev/null | sed -e 's#^.*/##' | awk '{print $1 "/"}'

基础示例:

_foo() 
{
    local cur prev opts flist
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    # Get all command words so far (omit command [0] element itself),remove spaces
    terms=`echo ${COMP_WORDS[@]:1} | sed -e 's/ //g'`

    # Get basenames (with trailing slashes) of matching dirs for completion
    flist=`ls -1 -d /root/sub1/sub2/sub3/${terms}* 2>/dev/null | sed -e 's#^.*/##' | awk '{print $1 "/"}' | xargs echo`

    COMPREPLY=( $(compgen -W "${flist}" ${cur}) )
    return 0
}
complete -F _foo foo
这似乎可以做你想要的:
_foo()
{
    local cur prev opts flist lastword new
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    lastword="${COMP_WORDS[@]: -1}"

    if [[ $lastword =~ / ]]
    then
        new="${lastword##*/}"      # get the part after the slash
        lastword="${lastword%/*}"  # and the part before it
    else
        new="${lastword}"
        lastword=""
    fi

    flist=$( command find /root/sub1/sub2/sub3/$lastword \
      -maxdepth 1 -mindepth 1 -type d -name "${new}*" \
      -printf "%f\n" 2>/dev/null )

    # if we've built up a path,prefix it to 
    #   the proposed completions: ${var:+val}
    COMPREPLY=( $(compgen ${lastword:+-P"${lastword}/"} \
      -S/ -W "${flist}" -- ${cur##*/}) )
    return 0
}
complete -F _foo -o nospace foo

笔记:

>我认为其中一个关键是nospace选项>我觉得我已经在上面的函数中重新创建了一个轮子,可能是因为没有使用$COMP_POINT>你不是(至少)使用$prev(在我的函数中始终保持值“foo”)>使用$()而不是反引号可以改善可读性和功能性>您应该使用命令来阻止运行别名等:flist = $(命令ls -1 -d …>我使用find代替ls,因为它更适合>您可以使用-S / with compgen而不是awk命令添加斜杠>你可以使用$cur而不是$terms,因为你不需要删除空格,但我使用$lastword和$new(两个新变量)>没有必要使用xargs echo,因为带有换行符的数组工作正常>我没有使用包含空格或换行符的目录名来测试它

猜你在找的Bash相关文章