bash 버그 - 탭 완성에서 일치하는 ""를 찾을 때 예기치 않은 EOF가 발생함

bash 버그 - 탭 완성에서 일치하는 ""를 찾을 때 예기치 않은 EOF가 발생함

이 질문에 대한 답변이 여러 번 나온 것으로 알고 있습니다.여기그리고여기.

그러나 그들은 모두 추가 오류를 언급했습니다.

나는 이런 식으로 간단한 awk 스크립트를 실행합니다.

awk -f test.awk -v time="$t" copy.out

이제 내가 입력할 때까지

awk -f test.awk -v time="$t" c #Press Tab after c

그런 다음 Tab 키를 눌러 Tab 키를 완성하면 오류가 발생합니다.

awk -f test.awk -v time="$t" cbash: unexpected EOF while looking for matching `"'
bash: syntax error: unexpected end of file

내 명령에는 적절한 수의 큰따옴표가 있습니다.탭 완성 없이 파일 이름을 입력한 다음 명령을 실행하면 제대로 작동하기 때문에 이것을 확실히 알고 있습니다.

내가 무엇을 놓치고 있나요?

bash -x위의 단계를 실행하고 수행 하면 다음과 같은 결과를 얻습니다.

word split
+ _init_completion -s
+ local exclude= flag outx errx inx OPTIND=1
+ getopts n:e:o:i:s flag -s
+ case $flag in
+ split=false
+ exclude+==
+ getopts n:e:o:i:s flag -s
+ COMPREPLY=()
+ local 'redir=@(?([0-9])<|?([0-9&])>?(>)|>&)'
+ _get_comp_words_by_ref -n '=<>&' cur prev words cword
+ local exclude flag i OPTIND=1
+ words=()
+ local cur cword words
+ upargs=()
+ upvars=()
+ local upargs upvars vcur vcword vprev vwords
+ getopts c:i:n:p:w: flag -n '=<>&' cur prev words cword
+ case $flag in
+ exclude='=<>&'
+ getopts c:i:n:p:w: flag -n '=<>&' cur prev words cword
+ [[ 6 -ge 3 ]]
+ case ${!OPTIND} in
+ vcur=cur
+ let 'OPTIND += 1'
+ [[ 6 -ge 4 ]]
+ case ${!OPTIND} in
+ vprev=prev
+ let 'OPTIND += 1'
+ [[ 6 -ge 5 ]]
+ case ${!OPTIND} in
+ vwords=words
+ let 'OPTIND += 1'
+ [[ 6 -ge 6 ]]
+ case ${!OPTIND} in
+ vcword=cword
+ let 'OPTIND += 1'
+ [[ 6 -ge 7 ]]
+ __get_cword_at_cursor_by_ref '=<>&' words cword cur
+ words=()
+ local cword words
+ __reassemble_comp_words_by_ref '=<>&' words cword
+ local exclude i j line ref
+ [[ -n =<>& ]]
+ exclude='=<>&'
+ printf -v cword %s 6
+ [[ -n =<>& ]]
+ line='awk -f test.awk -v time="$t" c'
+ (( i=0, j=0 ))
+ (( i < 7 ))
+ [[ 0 -gt 0 ]]
+ ref='words[0]'
+ printf -v 'words[0]' %s awk
+ line=' -f test.awk -v time="$t" c'
+ [[ 0 == 6 ]]
+ (( i++, j++ ))
+ (( i < 7 ))
+ [[ 1 -gt 0 ]]
+ [[ -f == +([=<>&]) ]]
+ ref='words[1]'
+ printf -v 'words[1]' %s -f
+ line=' test.awk -v time="$t" c'
+ [[ 1 == 6 ]]
+ (( i++, j++ ))
+ (( i < 7 ))
+ [[ 2 -gt 0 ]]
+ [[ test.awk == +([=<>&]) ]]
+ ref='words[2]'
+ printf -v 'words[2]' %s test.awk
+ line=' -v time="$t" c'
+ [[ 2 == 6 ]]
+ (( i++, j++ ))
+ (( i < 7 ))
+ [[ 3 -gt 0 ]]
+ [[ -v == +([=<>&]) ]]
+ ref='words[3]'
+ printf -v 'words[3]' %s -v
+ line=' time="$t" c'
+ [[ 3 == 6 ]]
+ (( i++, j++ ))
+ (( i < 7 ))
+ [[ 4 -gt 0 ]]
+ [[ time == +([=<>&]) ]]
+ ref='words[4]'
+ printf -v 'words[4]' %s time
+ line='="$t" c'
+ [[ 4 == 6 ]]
+ (( i++, j++ ))
+ (( i < 7 ))
+ [[ 5 -gt 0 ]]
+ [[ =" == +([=<>&]) ]]
+ ref='words[5]'
+ printf -v 'words[5]' %s '="'
+ line='$t" c'
+ [[ 5 == 6 ]]
+ (( i++, j++ ))
+ (( i < 7 ))
+ [[ 6 -gt 0 ]]
+ [[ $t" c == +([=<>&]) ]]
+ ref='words[6]'
+ printf -v 'words[6]' %s '$t" c'
+ line=
+ [[ 6 == 6 ]]
+ printf -v cword %s 6
+ (( i++, j++ ))
+ (( i < 7 ))
+ [[ 7 == 6 ]]
+ local i cur index=30 'lead=awk -f test.awk -v time="$t" c'
+ [[ 30 -gt 0 ]]
+ [[ -n awk -f test.awk -v time="$t" c ]]
+ [[ -n awk-ftest.awk-vtime="$t"c ]]
+ cur='awk -f test.awk -v time="$t" c'
+ (( i = 0 ))
+ (( i <= cword ))
+ [[ 30 -ge 3 ]]
+ [[ awk != \a\w\k ]]
+ [[ 0 -lt 6 ]]
+ local old_size=30
+ cur=' -f test.awk -v time="$t" c'
+ local new_size=27
+ index=27
+ (( ++i  ))
+ (( i <= cword ))
+ [[ 27 -ge 2 ]]
+ [[  - != \-\f ]]
+ cur='-f test.awk -v time="$t" c'
+ [[ 27 -gt 0 ]]
+ (( index-- ))
+ [[ 26 -ge 2 ]]
+ [[ -f != \-\f ]]
+ [[ 1 -lt 6 ]]
+ local old_size=26
+ cur=' test.awk -v time="$t" c'
+ local new_size=24
+ index=24
+ (( ++i  ))
+ (( i <= cword ))
+ [[ 24 -ge 8 ]]
+ [[  test.aw != \t\e\s\t\.\a\w\k ]]
+ cur='test.awk -v time="$t" c'
+ [[ 24 -gt 0 ]]
+ (( index-- ))
+ [[ 23 -ge 8 ]]
+ [[ test.awk != \t\e\s\t\.\a\w\k ]]
+ [[ 2 -lt 6 ]]
+ local old_size=23
+ cur=' -v time="$t" c'
+ local new_size=15
+ index=15
+ (( ++i  ))
+ (( i <= cword ))
+ [[ 15 -ge 2 ]]
+ [[  - != \-\v ]]
+ cur='-v time="$t" c'
+ [[ 15 -gt 0 ]]
+ (( index-- ))
+ [[ 14 -ge 2 ]]
+ [[ -v != \-\v ]]
+ [[ 3 -lt 6 ]]
+ local old_size=14
+ cur=' time="$t" c'
+ local new_size=12
+ index=12
+ (( ++i  ))
+ (( i <= cword ))
+ [[ 12 -ge 4 ]]
+ [[  tim != \t\i\m\e ]]
+ cur='time="$t" c'
+ [[ 12 -gt 0 ]]
+ (( index-- ))
+ [[ 11 -ge 4 ]]
+ [[ time != \t\i\m\e ]]
+ [[ 4 -lt 6 ]]
+ local old_size=11
+ cur='="$t" c'
+ local new_size=7
+ index=7
+ (( ++i  ))
+ (( i <= cword ))
+ [[ 7 -ge 2 ]]
+ [[ =" != \=\" ]]
+ [[ 5 -lt 6 ]]
+ local old_size=7
+ cur='$t" c'
+ local new_size=5
+ index=5
+ (( ++i  ))
+ (( i <= cword ))
+ [[ 5 -ge 5 ]]
+ [[ $t" c != \$\t\"\ \c ]]
+ [[ 6 -lt 6 ]]
+ (( ++i  ))
+ (( i <= cword ))
+ [[ -n $t" c ]]
+ [[ ! -n $t"c ]]
+ [[ 5 -lt 0 ]]
+ local words cword cur
+ _upvars -a7 words awk -f test.awk -v time '="' '$t" c' -v cword 6 -v cur '$t" c'
+ ((  15  ))
+ ((  15  ))
+ case $1 in
+ [[ -n 7 ]]
+ printf %d 7
+ [[ -n words ]]
+ unset -v words
+ eval 'words=("${@:3:7}")'
++ words=("${@:3:7}")
+ shift 9
+ ((  6  ))
+ case $1 in
+ [[ -n cword ]]
+ unset -v cword
+ eval 'cword="$3"'
++ cword=6
+ shift 3
+ ((  3  ))
+ case $1 in
+ [[ -n cur ]]
+ unset -v cur
+ eval 'cur="$3"'
++ cur='$t" c'
+ shift 3
+ ((  0  ))
+ [[ -n cur ]]
+ upvars+=("$vcur")
+ upargs+=(-v $vcur "$cur")
+ [[ -n cword ]]
+ upvars+=("$vcword")
+ upargs+=(-v $vcword "$cword")
+ [[ -n prev ]]
+ [[ 6 -ge 1 ]]
+ upvars+=("$vprev")
+ upargs+=(-v $vprev "${words[cword - 1]}")
+ [[ -n words ]]
+ upvars+=("$vwords")
+ upargs+=(-a${#words[@]} $vwords "${words[@]}")
+ ((  4  ))
+ local cur cword prev words
+ _upvars -v cur '$t" c' -v cword 6 -v prev '="' -a7 words awk -f test.awk -v time '="' '$t" c'
+ ((  18  ))
+ ((  18  ))
+ case $1 in
+ [[ -n cur ]]
+ unset -v cur
+ eval 'cur="$3"'
++ cur='$t" c'
+ shift 3
+ ((  15  ))
+ case $1 in
+ [[ -n cword ]]
+ unset -v cword
+ eval 'cword="$3"'
++ cword=6
+ shift 3
+ ((  12  ))
+ case $1 in
+ [[ -n prev ]]
+ unset -v prev
+ eval 'prev="$3"'
++ prev='="'
+ shift 3
+ ((  9  ))
+ case $1 in
+ [[ -n 7 ]]
+ printf %d 7
+ [[ -n words ]]
+ unset -v words
+ eval 'words=("${@:3:7}")'
++ words=("${@:3:7}")
+ shift 9
+ ((  0  ))
+ _variables
+ [[ $t" c =~ ^(\$(\{[!#]?)?)([A-Za-z0-9_]*)$ ]]
+ [[ $t" c =~ ^(\$\{[#!]?)([A-Za-z0-9_]*)\[([^]]*)$ ]]
+ [[ $t" c =~ ^\$\{[#!]?[A-Za-z0-9_]*\[.*]$ ]]
+ case $prev in
+ return 1
+ [[ $t" c == @(?([0-9])<|?([0-9&])>?(>)|>&)* ]]
+ [[ =" == @(?([0-9])<|?([0-9&])>?(>)|>&) ]]
+ local i skip
+ (( i=1 ))
+ (( i < 7 ))
+ [[ -f == @(?([0-9])<|?([0-9&])>?(>)|>&)* ]]
+ i=2
+ (( 1 ))
+ (( i < 7 ))
+ [[ test.awk == @(?([0-9])<|?([0-9&])>?(>)|>&)* ]]
+ i=3
+ (( 1 ))
+ (( i < 7 ))
+ [[ -v == @(?([0-9])<|?([0-9&])>?(>)|>&)* ]]
+ i=4
+ (( 1 ))
+ (( i < 7 ))
+ [[ time == @(?([0-9])<|?([0-9&])>?(>)|>&)* ]]
+ i=5
+ (( 1 ))
+ (( i < 7 ))
+ [[ =" == @(?([0-9])<|?([0-9&])>?(>)|>&)* ]]
+ i=6
+ (( 1 ))
+ (( i < 7 ))
+ [[ $t" c == @(?([0-9])<|?([0-9&])>?(>)|>&)* ]]
+ i=7
+ (( 1 ))
+ (( i < 7 ))
+ [[ 6 -le 0 ]]
+ prev='="'
+ [[ -n false ]]
+ _split_longopt
+ [[ $t" c == --?*=* ]]
+ return 1
+ return 0
+ case "${prev,,}" in
+ false
+ [[ $t" c == -* ]]
+ [[ awk == @(rmdir|chroot) ]]
+ [[ awk == mkdir ]]
+ _filedir
+ local 'IFS=
'
+ _tilde '$t" c'
+ local result=0
+ [[ $t" c == \~* ]]
+ return 0
+ local -a toks
+ local x tmp
++ compgen -d -- '$t" c'
+ x=
+ [[ '' != -d ]]
+ local quoted
+ _quote_readline_by_ref '$t" c' quoted
+ '[' -z '$t" c' ']'
+ [[ $t" c == \'* ]]
+ [[ $t" c == \~* ]]
+ printf -v quoted %q '$t" c'
+ [[ \$t\"\ c == *\\* ]]
+ printf -v quoted %s '$t" c'
+ [[ $t" c == \$* ]]
+ eval 'quoted=$t" c'
bash: unexpected EOF while looking for matching `"'
bash: syntax error: unexpected end of file
+ local xspec=
++ compgen -f -X '' -- '$t" c'
+ x=
+ [[ -n '' ]]
+ [[ 0 -ne 0 ]]

마지막 몇 줄에는 이라고 적혀 있지만 unquoted $t"전체 견적을 제공했고 작동했습니다. 그럼 이건 일종의 버그 아닌가요? 내 말은 bash가 내 시작 참조를 무시하거나 잘못 구문 분석하는 무모함을 가지고 있다는 것입니다.

답변1

bash -x출력 에서 bash-completion 패키지(bash-completion 의 일부는 아니지만 bash커뮤니티에서 관리하는 탭 완성 패키지)에 버그가 있음을 발견했습니다. 문제는 이 경우 bash 완료 실행이 다음으로 전달될 때 인용문을 올바르게 이스케이프하지 않는다는 것입니다 eval.

+ printf -v quoted %s '$t" c'
+ [[ $t" c == \$* ]]
+ eval 'quoted=$t" c'
bash: unexpected EOF while looking for matching `"'
bash: syntax error: unexpected end of file

버그 트래커를 보면 이렇게 보입니다.이 오류, 문제는 업스트림에서 수정되었지만 패치가 아직 저장소에 적용되지 않았습니다.

여러 가지 옵션이 있습니다:

  1. 배포판에 적합한 bash 완성 백포트를 찾으세요. 어떤 배포판에 문제가 있는지는 언급되어 있지 않지만 예를 들어 Ubuntu에서는 다음을 실행할 수 있습니다.암페타민.
  2. bash-completion 패키지 사용을 중단하고 bash의 내부 완성 로직을 사용하세요. 탭 완성이 필요한 작업에 따라 이것으로 충분할 수도 있습니다.
  3. 수정 사항이 배포 저장소에 적용될 때까지 기다리십시오. 배포판에 따라 수정하는 데 걸리는 시간은 "5분 이내"에서 "안 함"까지 다양할 수 있습니다.
  4. 배포판에 업스트림 수정 사항을 백포트하는 프로세스가 있는 경우 새 릴리스를 기다리는 대신 이 수정 사항을 적용하도록 백포트 패치를 요청하는 것을 고려할 수 있습니다. 관리자와 배포판의 정책에 따라 이것이 작동할 수도 있고 작동하지 않을 수도 있습니다.

관련 정보