使用可变隐藏根前缀完成 Tcsh 和/或 bash 目录
我正在尝试在 tcsh 和/或 bash(两者都在我的网站上使用)中设置目录完成,但略有不同:对于特定命令“foo”,我希望完成使用自定义函数来匹配第一个 / 分隔的术语到实际的子树节点,然后遵循正常的目录完成任何连续的术语。它是 cdpath 和完成的组合,或者我认为是一种目录完成形式,其中起点由完成脚本控制。它的工作原理如下:
$ 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 生产设施),精通 shell 的用户一直在其中导航和跳跃。人们抱怨树的上层是繁琐且多余的;他们只需要快速搜索第一个术语即可找到可能的“头”选择并从那里完成目录补全。可编程完成似乎可以提供一种方法来做到这一点,但事实证明它相当难以捉摸。
我已经多次尝试自定义 bash 和 tcsh 完成来做到这一点,但我得到的最接近的是“单词完成”的形式,其中用户必须将目录级别视为带有空格的单独单词(例如 foo scene/ shot /元素/工作区/ ...)。我可以继续修改我当前的脚本 - 但我一直想知道是否有一些我不理解的东西 - 这是我第一次尝试完成程序,并且 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 "/"}'
bash 示例:
_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
I'm trying to set up directory completion in tcsh and/or bash (both are used at my site) with a slight twist: for a particular command "foo", I'd like to have completion use a custom function to match the first /-delimited term to an actual subtree node, and then follow normal directory completion for any successive terms. It is sort of a combination of cdpath and completion, or I suppose a form of directory completion where the starting point is controlled by the completion script. It would work as follows:
$ 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/...
We'd like to do this because we have a large production development tree (this is a CGI production facility), that shell-savvy users are navigating and jumping around in all the time. The complaint is that the upper levels of the tree are cumbersome and redundant; they just need a quick search on the first term to find possible "head" choices and do directory completion from there. It seems like programmable completion could offer a way to do this, but it is turning out to be pretty elusive.
I've made several attempts of custom bash and tcsh completion to do this, but the closest I've gotten is a form of "word completion" where the user must treat the directory levels as separate words with spaces (e.g. foo scene/ shot/ element/ workspace/ ...). I could continue hacking at my current scripts--but I've been wondering if there's something I'm not understanding--this is my first attempt to program completion, and the docs and examples are pretty thin in shell books and on the internet. If there's any completion-guru's out there that can get me on the right track, I'd appreciate it.
FWIW: here is what I've got so far (in tcsh first, then bash). Note that the static root '/root/sub1/sub2/sub3' is just a placeholder for a search function that would find different matches in different levels. If I can get that to work, I can sub in the search feature later. Again, both examples do word completion, which requires user to type a space after each matching term (I also have to remove the spaces in the function to construct an actual path, yuck!)
TCSH EXAMPLE (note the function is actually a bash script):
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 "/"}'
BASH EXAMPLE:
_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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这似乎可以满足您的需求:
注意:
$COMP_POINT
$prev
(它始终在我的函数中维护值“foo”)$()
而不是反引号command
来防止运行别名等:flist=$(command ls -1 -d...
find
而不是ls
因为它更适合-S/
和compgen< 添加斜线/code> 而不是
awk
命令$cur
而不是$terms
因为您不必删除空格,但是我正在使用$lastword
和$new
(两个新变量)xargs echo
因为带有换行符的数组工作正常This seems like it might do what you're looking for:
Notes:
nospace
option$COMP_POINT
$prev
(which always maintains the value "foo" in my function)$()
instead of backtickscommand
to prevent running aliases and such:flist=$(command ls -1 -d...
find
instead ofls
because it's better suited-S/
withcompgen
instead of yourawk
command$cur
instead of$terms
since you don't have to strip out spaces, but I'm using$lastword
and$new
(two new variables)xargs echo
since an array with newlines works fine我的解决方案(无疑是一把 800 磅的锤子)是编写一个 Perl 脚本来按照我想要的方式处理完成。在 tcsh...
my solution, which is admittedly an 800-lb hammer, was to write a perl script to handle the completion the way i wanted it to. in tcsh...
所以,这是一个 tcsh 解决方案。添加完整的 $cdpath 搜索自动完成目录。完整的命令是:
我有点tcsh hack,所以字符串操作有点粗糙。但它的工作开销可以忽略不计... mycdpathcomplete.csh 看起来像这样:
So, here is a tcsh solution. Adds full $cdpath searching for autocompleting directories. The complete command is:
I am a bit of a tcsh hack, so the string manipulation is a bit crude. But it works with negligible overhead... mycdpathcomplete.csh looks like this:
您可以创建指向树中第一个有趣节点的符号链接。过去,当我懒得自动完成大型目录树时,我就这样做过。
You could just make a symlink to the first interesting node in the tree. I've done this in the past when I couldn't be bothered auto-completing large directory trees.
基本的 tcsh 解决方案非常容易实现,如下所示:
不需要 bash 脚本依赖项。当然,在此示例中基本目录是硬连线的。
The basic
tcsh
solution is very easy to implement as follows:There is no
bash
script dependency required. Of course the base directory is hardwired in this example.