실제로 여기에 게시하기 전에 이 문제를 해결하기 위해 정말 열심히 노력했지만 이 특정 문제를 해결한 다른 사람의 예를 찾을 수 없는 것 같습니다.
우분투 17.10을 실행 중입니다.
내 스크립트 중 하나에 대한 탭 완성을 처리하는 사용자 정의 함수를 작성했습니다. 그 목적은 스크립트 이름을 입력하고 [TAB]을 누르면 ".use"로 끝나는 /opt/use의 모든 파일이 나열된다는 것입니다(".use" 또는 선행 경로는 표시되지 않음). 나는 지금까지 이것을 달성한 것 같다.
/opt/use 아래의 파일은 다음과 같습니다.
blender-2.79.use
chrome.use
clarisse-3.6.use
unity-2017.3.0p2.use
함수와 완성된 코드는 다음과 같습니다.
_use () {
files=( `compgen -f -X "!*.use" /opt/use/` )
output=()
for file in "${files[@]}"; do
fileBaseName=`basename $file .use`
output+=("$fileBaseName")
done
COMPREPLY=( ${output[@]} )
}
complete -F _use use
저를 너무 가혹하게 판단하지 마세요. 저는 프로그래머가 아니라 그래픽 아티스트입니다. :)
또한 내 "use" 스크립트는 실제로 다음 명령의 별칭입니다.
source /opt/scripts/use.sh
이제 다음을 입력하면:
use[SPACE][TAB][TAB]
/opt/use에서 ".use"로 끝나는 파일 목록을 성공적으로 얻었습니다.
여태까지는 그런대로 잘됐다. 예를 들어 "use[SPACE][TAB][TAB]"를 입력하면 다음과 같습니다.
bvz@bvz-xps15-linux:~$ use
blender-2.79 chrome clarisse-3.6 unity-2017.3.0p2
첫 번째 질문은 왜 [TAB]을 두 번 눌러야 합니까?입니다. 처음에는 경고음만 들립니다. 두 번째로 나에게 옵션이 제시되었습니다. 이것은 나에게 문제가 되지 않습니다. 이것이 내 문제에 대한 단서인지 궁금합니다.
완전히 고유하게 만들 만큼 충분한 문자를 입력하면 탭 완성 기능이 실제로 줄을 "완성"하지 않습니다. 내가 입력한 대로 정확하게 항목을 만들고 /opt/use에 파일 목록을 다시 표시합니다. 예를 들어, 다음과 같이 입력하면:
use clar[TAB][TAB]
읽을 행을 채우는 대신:
use clarisse-3.6
이것이 내가 기대하는 것(그리고 내가 추구하는 것)이며 행을 다음과 같이 유지합니다.
use clar
그리고 나에게 할 수 있는 일의 전체 목록을 보여주었습니다. 예는 다음과 같습니다.
bvz@bvz-xps15-linux:~$ use clar[TAB][TAB]
blender-2.79 chrome clarisse-3.6 unity-2017.3.0p2
bvz@bvz-xps15-linux:~$ use clar
가능한 유일한 완료임에도 불구하고 "clarisse-3.6"에 대한 줄 읽기가 실제로 완료되지는 않습니다.
누구든지 내가 뭘 잘못하고 있는지 말해 줄 수 있나요? 또한 중복이라면 사과드립니다. 며칠 동안 주변을 둘러봤지만 이 문제를 해결하는 것은커녕 이 문제에 직면한 사람의 사례를 찾을 수 없습니다.
감사해요
답변1
해결책을 알려준 Muru에게 감사드립니다.
분명히 내 문제는 내 함수가 호출될 때마다 항상 가능한 일치 항목의 전체 목록을 반환한다는 것입니다. 사용자가 지금까지 입력한 내용과 일치하는 가능한 완성 항목을 반환하면 됩니다. 항목 하나만 반환하면 bash는 자동으로 나머지 줄을 완성합니다.
이것은 유효한 기능입니다. 가능한 각 완성을 추가하기 전에 원래 입력한 단어로 완성이 시작되는지 빠르게 확인합니다. 저는 이를 위해 정규 표현식을 사용합니다. 또한 아직 아무것도 입력하지 않았는지 테스트해야 합니다. 이 경우 항상 모든 것을 반환합니다.
또한 더 많은 변수를 "로컬"로 만들기 위해 변경했습니다.
_use () {
local word="${COMP_WORDS[$COMP_CWORD]}"
local files=( `compgen -f -X "!*.use" /opt/use/` )
local output=()
for file in "${files[@]}"; do
fileBaseName=`basename $file .use`
if [[ $fileBaseName =~ ^$word.* ]] || [ "$word" == "" ]; then
output+=("$fileBaseName")
fi
done
COMPREPLY=( ${output[@]} )
}
답변2
이제 이것에 대해 생각할 시간을 가졌으니 완성 기능을 다음과 같이 단순화할 수 있다고 생각합니다.
_use () {
local word="${COMP_WORDS[$COMP_CWORD]}"
local IFS=$'\n'
COMPREPLY=( $(find /opt/use/ -type f -name "$word*.use" -exec basename -as .use {} +) )
}
basename
새 버전이 이를 지원하기에 충분하다고 가정하고 -a
, 그렇지 않으면 다음을 수행하십시오 -exec basename {} .use \;
.