我正在尝试编写一个 Bash 完成脚本,该脚本在存在冒号的情况下不会中断。为此,我使用 COMP_LINE 来确定命令的字符串,并使用 COMP_POINT 作为用户当前指向命令中哪个字符的索引。
使用这两个变量,我想计算出用户当前正在尝试完成哪个单词。这通常使用 COMP_WORDS 数组来完成,其中 COMP_CWORD 变量充当指向该数组的指针。问题是,COMP_WORDS 在冒号上分割字符串,因此命令如下:
dothis foo:bar
读入 COMP_WORDS 为:
('dothis' 'foo' ':' 'bar')
我不想要这种行为,所以我正在解决它。
假设我有一个命令存储在 Bash 变量中,如下所示:
apple banana carrot:cucumber durian
我目前对上述问题的解决方案如下。解释在代码下面,老实说我认为代码更简单。
#!/bin/bash
str="apple banana carrot:cucumber durian"
cur=29
char=${str:$cur:1} # Current character being pointed to
prev=${str:$cur-1:1} # Previous character
if [[ $char == [[:space:]] ]]; then
if [[ $prev == [[:space:]] ]]; then
# Rule 1 - Char and prev are whitespace
# apple banana carrot:cucumber durian
# ^ Char = ' ' Prev = ' '
word=""
else
# Rule 2 - Char is whitespace, prev is not
# apple banana
# ^ Char = ' ' Prev = 'e'
# Means prev is the last character of the word
slice="${str::$cur}"
word="${slice##* }" # 'apple'
fi
else
if [[ $prev == [[:space:]] ]]; then
# Rule 3 - Char is not whitespace, prev is whitespace
# apple banana carrot:cucumber
# ^ Char = 'c' Prev = ' '
slice="${str:$cur}"
word="${slice%% *}" # 'carrot:cucumber'
else
# Rule 4 - Char and prev are not whitespace
# apple banana
# ^ Char = 'a' Prev = 'n'
end="${str:$cur}"
end="${end#* }"
slice="${str% $end}"
word="${slice##* }" # 'banana'
fi
fi
echo "Word: <$word>"
其作用如下。它检查索引处的字符 (char) 及其之前的字符 (prev),并遵循以下四个规则来确定当前指向哪个单词:
如果 char 和 prev 都是空白字符,则将 'word' 设置为空
如果 char 是空格但 prev 是非空格字符,则将 'prev' 作为单词的结尾。提取一个子字符串直到 prev,然后删除从该子字符串开头到(包括空格)的所有内容。
如果 char 是非空白字符但 prev 是空白,则将 'char' 作为单词的开头。提取直到 prev 的子字符串,然后删除从子字符串末尾直到(包括空格)的所有内容。
如果 char 和 prev 都是非空白字符,则将 'char' 视为单词的中间或结尾。首先抓取从“char”到字符串末尾的子字符串,然后从该子字符串的开头删除最短的文本实例,直到包含空格。然后删除那从原始字符串中提取子字符串,以获取单词的所有内容。最后来自那子字符串,删除所有内容(包括空格)以获取单词。
基本上我不相信这是最有效的解决方案。即使用问题来描述也很复杂。当然有一些更好、更奇特的方法可以根据该单词的索引从字符串中获取整个单词?
任何人都可以提供关于解决此问题的更好方法的建议,或者如果没有,有什么方法可以优化我的解决方案吗?