加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

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

发布时间:2020-12-16 01:20:41 所属栏目:安全 来源:网络整理
导读:我正在尝试在tcsh和/或bash中设置目录完成(两者都在我的网站上使用)稍微扭曲:对于特定命令“foo”,我想完成使用自定义函数来匹配first / -deimited term到实际子树节点,然后按照正常目录完成任何连续的术语.它是cdpath和completion的组合,或者我想是一种目
我正在尝试在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 "%fn" 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,因为带有换行符的数组工作正常>我没有使用包含空格或换行符的目录名来测试它

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读