【发布时间】:2021-07-10 08:37:48
【问题描述】:
我在 bash 中有一个名为 comp_line 的字符串,其中可以包含任意数量的空格。例如:
"foo bar apple banana q xy"
我有一个从零开始的索引 comp_point 指向该字符串中的一个字符,例如如果comp_point 为 4,则指向 'bar' 中的第一个 'b'。
仅基于comp_point 和comp_line,我想提取索引指向的单词,其中“单词”是字母、数字、标点符号或任何其他非空白字符的序列,两边被空格包围(如果单词在字符串的开头或结尾,或者是字符串中唯一的单词,它应该以相同的方式工作。)
我要提取的单词将变为cur(当前单词)
基于此,我想出了一套规则:
读取当前字符curchar、前一个字符prevchar和下一个字符nextchar。那么:
-
如果
curchar是图形字符(非空格),请将cur设置为curchar之前和之后的字母(停止,直到您到达任一侧的空格或字符串开始/结束。) -
否则,如果
prevchar是图形字符,则将cur设置为前一个字母的字母,向后直到前一个空白字符/字符串开始。 -
否则,如果
nextchar是图形字符,则将cur设置为从下一个字母开始的字母,直到下一个空白字符/字符串结束。 -
如果以上条件都没有满足(意思是
curchar、nextchar和prevchar都是空白字符)设置cur为""(空字符串)
我编写了一些我认为可以实现这一点的代码。规则 2、3 和 4 相对简单,但规则 1 是最难实现的——我不得不进行一些复杂的字符串切片。我不相信我的解决方案在任何方面都是理想的,并且想知道是否有人知道仅在 bash 中执行此操作的更好方法(而不是外包给 Python 或其他更简单的语言。)
在https://rextester.com/l/bash_online_compiler上测试
#!/bin/bash
# GNU bash, version 4.4.20
comp_line="foo bar apple banana q xy"
comp_point=19
cur=""
curchar=${comp_line:$comp_point:1}
prevchar=${comp_line:$((comp_point - 1)):1}
nextchar=${comp_line:$((comp_point + 1)):1}
echo "<$prevchar> <$curchar> <$nextchar>"
if [[ $curchar =~ [[:graph:]] ]]; then
# Rule 1 - Extract current word
slice="${comp_line:$comp_point}"
endslice="${slice%% *}"
slice="${slice#"$endslice"}"
slice="${comp_line%"$slice"}"
cur="${slice##* }"
else
if [[ $prevchar =~ [[:graph:]] ]]; then
# Rule 2 - Extract previous word
slice="${comp_line::$comp_point}"
cur="${slice##* }"
else
if [[ $nextchar =~ [[:graph:]] ]]; then
# Rule 3 - Extract next word
slice="${comp_line:$comp_point+1}"
cur="${slice%% *}"
else
# Rule 4 - Set cur to empty string ""
cur=""
fi
fi
fi
echo "Cur: <$cur>"
当前示例将返回 'banana',因为 comp_point 设置为 19。
我确信一定有一种我没有想到的更简洁的方法,或者我错过了一些技巧。到目前为止它也有效,但我认为可能有一些我没有想到的极端情况。谁能告诉我是否有更好的方法?
(XY 问题,如果有人问的话)
我正在编写一个制表符完成脚本,并尝试使用 COMP_LINE 和 COMP_POINT 模拟 COMP_WORDS 和 COMP_CWORD 的功能。当用户键入命令以完成制表符时,我想仅根据后两个变量来确定他们尝试制表符完成的单词。我不想将此代码外包给 Python,因为当 Python 参与制表符完成时,性能会受到很大影响。
【问题讨论】:
-
看到有人花这么多精力写一个问题真是令人耳目一新。谢谢你。但是,我想知道您为什么不首先使用
COMP_CWORD。这可能是另一个/实际的 XY 问题吗? -
谢谢!更广泛的上下文是:bash 制表符补全有一个怪癖,它根据
COMP_WORDBREAKS的内容将命令词拆分为COMP_WORDS,其中包含冒号和其他几个字符。我正在为使用冒号编写完成的命令。我不得不设计一个迂回的解决方案,其中包括将COMP_WORDS加入单个字符串并再次将其拆分为空格。但随后我需要正确识别用户光标的位置,如果用户选择的是空格字符,请将空字符串添加回COMP_WORDS的正确位置。