我想知道这在Bash中是否可行,但我想使用制表符完全替换正在扩展的当前参数。 我举个例子: 我想要一个在树中向上移动任意数量级别的函数,所以我可以调用 2 这会打开我2个目录。 但是,我想这样做,如果在数字2,我按Tab键,它会将该数字扩展为路径(相对或绝对,或者很好)。 我有几乎使用完整的内置工作,除了它只会附加文本,所以它将是类似的东西 up 2 / Volumes / Dev /
是否可以替换已完成的符号?
提前致谢:)
非常感谢chepner,因为实际检查我的代码揭示了我的bug所在。我正在与错误的var进行比较,而我的调试代码导致值无法替换。
对于任何有兴趣的人,这里是代码(并且可能有更好的方法来实现这一点):
# Move up N levels of the directory tree
# Or by typing in some dir in the PWD
# eg. Assuming your PWD is "/Volumes/Users/natecavanaugh/Documents/stuff"
# `up 2` moves up 2 directories to "/Volumes/Users/natecavanaugh"
# `up 2/` and pressing tab will autocomplete the dirs in "/Volumes/Users/natecavanaugh"
# `up Users` navigate to "/Volumes/Users"
# `up us` and pressing tab will autocomplete to "/Volumes/Users"
function up {
dir="../"
if [ -n "$1" ]; then
if [[ $1 =~ ^[0-9]+$ ]]; then
strpath=$( printf "%${1}s" );
dir=" ${strpath// /$dir}"
else
dir=${PWD%/$1/*}/$1
fi
fi
cd $dir
}
function _get_up {
local cur
local dir
local results
COMPREPLY=()
#Variable to hold the current word
cur="${COMP_WORDS[COMP_CWORD]}"
local lower_cur=`echo ${cur##*/} | tr [:upper:] [:lower:]`
# Is the arg a number or number followed by a slash
if [[ $cur =~ ^[0-9]+/? ]]; then
dir="../"
strpath=$( printf "%${cur%%/*}s" );
dir=" ${strpath// /$dir}"
# Is the arg just a number?
if [[ $cur =~ ^[0-9]+$ ]]; then
COMPREPLY=($(compgen -W "${dir}"))
else
if [[ $cur =~ /.*$ ]]; then
cur="${cur##*/}"
fi
results=$(for t in `cd $dir && ls -d */`; do if [[ `echo $t | tr [:upper:] [:lower:]` == "$lower_cur"* ]]; then echo "${t}"; fi done)
COMPREPLY=($(compgen -P "$dir" -W "${results}"))
fi
else
# Is the arg a word that we can look for in the PWD
results=$(for t in `echo $PWD | tr "/" "\n"`; do if [[ `echo $t | tr [:upper:] [:lower:]` == "$lower_cur"* ]]; then echo "${t}"; fi; done)
COMPREPLY=($(compgen -W "${results}"))
fi
}
#Assign the auto-completion function _get for our command get.
complete -F _get_up up
答案 0 :(得分:2)
以下内容基于问题中OP自己的代码构建:
\
的目录名称 - 正确转义 - 例如,带有嵌入空格的名称 - 正确;如果指定了无效的目录名(未完成),则报告错误修改后的例子是:
/
这是完整的代码(注意语法着色表示格式错误的代码,但事实并非如此):
# Assume that the working directory is '/Users/jdoe/Documents/Projects/stuff'.
# `up 2` moves 2 levels up to '/Users/jdoe/Documents'
# `up 2<tab>` completes to `up /Users/jdoe/Documents/`
# Hit enter to change to that path or [type additional characters and]
# press tab again to complete based on subdirectories.
# `up Documents` or `up documents` changes to '/Users/jdoe/Documents'
# `up Doc<tab>` or `up doc<tab>` completes to `up /Users/jdoe/Documents/`
# Hit enter to change to that path or [type additional characters and]
# press tab again to complete based on subdirectories.
# Note: Case-insensitive completion is only performed if it is turned on
# globally via the completion-ignore-case Readline option
# (configured, for instance, via ~/.inputrc or /etc/inputrc).
答案 1 :(得分:2)
可以用一个新单词完全替换当前单词。用我的bash 4.2.29,我可以这样做:
_xxx() { COMPREPLY=( foo ); }
complete -F _xxx x
x bar # pressing tab turns this into x foo
但是,如果有多个可能的完成,并且您希望部分完成公共前缀,则会遇到问题。然后我的实验表明bash会尝试将可用的完成次数与您输入的前缀相匹配。
所以一般来说,如果某些内容是唯一定义的,你应该只用一些完全不同的东西替换当前的参数。否则,您应该生成与当前前缀匹配的完成,以便用户从中选择。在您的情况下,您可以用以下内容替换COMPREPLY=($(compgen -P "$dir" -W "${results}"))
:
local IFS=$'\n'
COMPREPLY=( $(find "${dir}" -maxdepth 1 -type d -iname "${cur#*/}*" -printf "%P\n") )
if [[ ${#COMPREPLY[@]} -eq 1 ]]; then
COMPREPLY=( "${dir}${COMPREPLY[0]}" )
fi
但是,在这种特定情况下,最好只用适当的路径替换前缀数字,并将其他所有内容保留为默认的bash完成:
_up_prefix() {
local dir cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY=()
if [[ ${cur} =~ ^[0-9]+/? ]]; then
# Starting with a number, possibly followed by a slash
dir=$( printf "%${cur%%/*}s" );
dir="${dir// /../}"
if [[ ${cur} == */* ]]; then
dir="${dir}${cur#*/}"
fi
COMPREPLY=( "${dir}" "${dir}." ) # hack to suppress trailing space
elif [[ ${cur} != */* ]]; then
# Not a digit, and no slash either, so search parent directories
COMPREPLY=( $(IFS='/'; compgen -W "${PWD}" "${cur}") )
if [[ ${#COMPREPLY[@]} -eq 1 ]]; then
dir="${PWD%${COMPREPLY[0]}/*}${COMPREPLY[0]}/"
COMPREPLY=( "${dir}" "${dir}." ) # hack as above
fi
fi
}
complete -F _up_prefix -o dirnames up
代码变得更容易阅读和维护,而且启动效率更高。唯一的缺点是,在某些情况下,您必须再次按Tab键一次:一次替换前缀,再多两次以实际查看可能的完成列表。您的选择是否可以接受。
还有一件事:完成将把参数转换为常规路径,但是你的up函数不接受它们。所以也许您应该使用[[ -d $1 ]]
检查启动该功能,如果存在则只需cd到该目录。否则,您的完成将生成对被调用函数不可接受的参数。