我正在写bash来处理目录中的文件。我有一些基本(相当长的)路径要处理。我想通过选项和参数指定一个子路径并使它自动完成。我的意思是这样的:
#!/bin/bash
dir=~/path/to/base/dir
while getopts ":d:" opt; do
case $opt in
d)
dir=$dir/$OPTARG
;;
#invalid input handling
esac
done
但是在此实现中,参数不是自动完成的,我必须自己键入子目录的所有名称(Tab
不起作用)。
有什么办法可以做到这一点吗?
是的,可以从命令行选项标志指定的自定义基本目录中实现路径补全。这是一个说明如何完成此操作的小示例。首先,我将略微修改您的示例脚本,以使演示更加有趣(即产生输出):
#!/bin/bash
# echo_path.sh
#
# Echoes a path.
#
# Parse command-line options
while getopts ":d:" opt; do
# Use '-d' to specify relative path
case "${opt}" in
d)
directory="${OPTARG}"
;;
esac
done
# Print the full path
echo "$(readlink -f ${directory})"
这基本上与您的示例脚本相同,但是会打印出给定的参数。
接下来,我们需要编写一个由Bash程序完成系统调用的函数。这是定义此类功能的脚本:
# echo_path_completion.bash
# Programmatic path completion for user specified file paths.
# Define a base directory for relative paths.
export BASE_DIRECTORY=/tmp/basedir
# Define the completion function
function _echo_path_completion() {
# Define local variables to store adjacent pairs of arguments
local prev_arg;
local curr_arg;
# If there are at least two arguments then we have a candidate
# for path-completion, i.e. we need the option flag '-d' and
# the path string that follows it.
if [[ ${#COMP_WORDS[@]} -ge 2 ]]; then
# Get the current and previous arguments from the command-line
prev_arg="${COMP_WORDS[COMP_CWORD-1]}";
curr_arg="${COMP_WORDS[COMP_CWORD]}";
# We only want to do our custom path-completion if the previous
# argument is the '-d' option flag
if [[ "${prev_arg}" = "-d" ]]; then
# We only want to do our custom path-completion if a base
# directory is defined and the argument is a relative path
if [[ -n "${BASE_DIRECTORY}" && ${curr_arg} != /* ]]; then
# Generate the list of path-completions starting from BASE_DIRECTORY
COMPREPLY=( $(compgen -d -o default -- "${BASE_DIRECTORY}/${curr_arg}") );
# Don't append a space after the command-completion
# This is so we can continue to apply completion to subdirectories
compopt -o nospace;
# Return immediately
return 0;
fi
fi
fi
# If no '-d' flag is given or no base directory is defined then apply default command-completion
COMPREPLY=( $(compgen -o default -- "${curr_arg}") );
return 0;
}
# Activate the completion function
complete -F _echo_path_completion echo_path
现在让我们获取完成脚本的源代码:
source echo_path_completion.bash
让我们使脚本可执行,并将其移动到PATH中的某个位置:
chmod +x echo_path.bash
mv -i echo_path.bash /usr/local/bin
最后,让我们为脚本添加一个别名,该别名没有文件扩展名:
alias echo_path=echo_path.bash
现在,如果您输入echo -d
并单击选项卡按钮,则应该从BASE_DIRECTORY开始获取文件路径的完成。要对此进行测试,您可以尝试以下操作:
mkdir -p ${BASE_DIRECTORY}
mkdir -p "${BASE_DIRECTORY}/file"{1..5}
当您点击选项卡时,您应该获得以下完成列表:
user@host:~$ echo_path -d
user@host:~$ echo_path -d /tmp/basedir/file
/tmp/basedir/file1 /tmp/basedir/file2 /tmp/basedir/file3 /tmp/basedir/file4 /tmp/basedir/file5
请注意,在第一个选项卡之后,字符串将转换为绝对路径。您可以根据需要更改此设置,但我认为这可能是更可取的做法。
这里是一些参考资料,您可以参考以获取更多信息。
有关官方参考,请查看Bash手册的以下部分:
部分:5.2 Bash变量(查找带有COMP_
前缀的变量)
另请参阅Linux Documentation Project的Advanced Bash脚本指南:
要快速了解Bash中的程序化补全的某些功能,请参阅“ The Geek Stuff”网站上的这篇文章:
还有一些相关的StackOverflow帖子可能对您有用:
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句