Bash에서 중괄호를 사용할 때 탭 완성을 얻는 방법

Bash에서 중괄호를 사용할 때 탭 완성을 얻는 방법

Bash의 명령에서 중괄호를 사용할 때 탭 완성 기능을 사용하고 싶습니다.

예를 들어:

cp ~/html/{foo bar.txt whatever} /var/www/html/

중괄호 안에 지정된 파일의 탭 완성을 원합니다.

답변1

이를 해석하는 방법에는 두 가지가 있습니다. end 앞에 이름을 입력하면 완성을 원합니다 }(다른 디렉토리에서 파일 완성을 효과적으로 수행). 또는 확장이 완료되고 end 뒤의 (유효한) 이름을 바꾸려고 합니다 }. { }확장은 확장된 글로빙과 달리 모든 옵션을 확장합니다.기존의파일 이름을 지정하되 공백 대신 ","를 사용하세요.

{}Bash를 사용하여 단어 목록을 만드는 예상 방법은 다음과 같습니다.

cp ~/html/{foo,bar.txt,whatever}  ...

두 가지 옵션이 있습니다. readline 키 바인딩을 쉘 함수에 연결하거나 프로그래밍 방식으로 수행하는 것입니다.

readline 방법을 사용하면 현재 명령을 완전히 다시 작성할 수 있지만 문제는 현재 명령줄을 표시하지 않으므로 파싱 문제가 적지 않다는 것입니다.

프로그래밍 가능한 완성하다path/{명령줄을 토큰화하지만 현재 단어만 수정/바꿀 수 있습니다. 즉, 편집 중에 접두사를 (쉽게) 유지할 수 없습니다 .

관련된 유일한 기본 bash 기능은 bash가 기본적으로 (Esc ) 에 바인딩된 "모든 쉘 단어 확장"을 수행한다고 주장하는 readline기능 입니다. 이러한 확장은 매뉴얼 페이지(bash-4.3)에 표시된 7가지 확장 유형 모두일 것이라고 합리적으로 기대할 수 있습니다.shell-expand-line\M-\C-e\C-e

Expansion is performed on the command line after it has been split into
words.   There are seven kinds of expansion performed: brace expansion,
tilde expansion, parameter and variable  expansion,  command  substitu‐
tion, arithmetic expansion, word splitting, and pathname expansion.

입력하여 실험해 볼 수 있습니다(Enter를 누를 필요 없음).

echo {1..2} ~root $0 $LANG `echo foo` $((1+2) "a b" /etc/p[aeiou]*

그런 다음 MetaCtrlE(+ 메타 장애가 있는 키보드를 사용하는 경우 ESC).CtrlE

첫 번째와 마지막(중괄호 및 경로) 확장이 모두 작동하지 않으므로 문서 및 구현이 IMHO와 일치하지 않습니다.

다음은 확장 탭을 사용하는 완전한 솔루션이 아닌 해결 방법입니다. 그러나 올바른 중괄호 확장 구문을 사용해야 하며, 특히 공백이 아닌 쉼표를 사용하여 항목을 구분해야 합니다.

function _expand() {
   [[ -z "${READLINE_LINE}" ]] && return
   eval local aa=( ${READLINE_LINE} )       # not-quoted, eval needed
   [[ ${#aa} -eq 0 ]] && return             # parse problem
   printf -v READLINE_LINE "%s " "${aa[@]}"
   READLINE_POINT=${#READLINE_LINE}         # eol, predictable at least
}

bind -x '"\C-_":_expand'

이는 배열을 채우고 모든 정상적인 확장(위에서 언급한 기록 제외)이 발생하도록 한 다음 명령줄을 다시 작성하는 Ctrl_bash 함수와 연결되어 있습니다.eval

입력을 시작하고, Ctrl_뭔가를 확장하고 싶을 때 클릭하고, Return준비가 되면 일반 키를 누르세요.

이는 탭보다 강력하지만 전체 입력 줄을 확장하므로 정확도가 떨어집니다. 특히 다양한 셸 메타 문자가 간단한 eval논리를 난독화하는 경우에는 예상대로 확장되지 않는 경우도 있습니다 .

zshBash 솔루션을 과도하게 엔지니어링하는 대신 Gille의 제안을 살펴볼 가치가 있습니다.

답변2

CtrlUbuntu(16.04) 터미널에서 + 작업을 수행하면 {디렉터리 {의 파일을 사용하여 중괄호가 자동으로 완성됩니다. 파일을 구분하기 위해 공백 대신 쉼표를 사용합니다. 예를 들어 다음 파일이 포함된 디렉터리입니다. file.cpp file.h file.i file.py file_wrap.cxx

...자동으로 수행됩니다. $ cp file{.{cpp,h,i,py},_wrap.cxx}

답변3

이 맥락에서 중괄호(정의상 "중괄호"임)는 쉼표로 구분된 텍스트 조각 목록을 나타냅니다. 파일 이름에 가장 일반적으로 사용되지만 확장됩니다.앞으로파일 이름 확장자를 처리합니다. 따라서 bash실제로 파일 이름을 입력하고 있는지 알 수 있는 방법이 없기 때문에 명시적인 확장 기능이 없습니다 .

답변4

OP가 탭 이후의 줄 완성 동작을 직접 관찰하고 반환 이후의 구문 분석 동작을 비교할 수 있는 진단 도구를 제공했습니다. 관찰 및 분석 후에 중괄호 기능을 완성하기 위해 줄 완성 함수를 작성하는 것이 가능하지만 bash는 중괄호 이후의 추가 줄 완성 기능을 억제하도록 제한하므로 이는 의미가 없다는 결론을 내릴 수 있습니다.

다음 bash 스크립트를 사용하면 진단이 가능합니다.

#!/bin/bash

confirm_args(){
    logger -t "confirm_args" -- "#=${#}"
    for index in `seq 0 ${#}` ; do
        eval item=\$$index
        logger -t "confirm_args" -- "[$index] ${item}"
    done    
}

_foo_completion(){
    logger -t "_foo_completion" -- "COMP_CWORD=${COMP_CWORD}" 
    logger -t "_foo_completion" -- "#COMP_WORDS=${#COMP_WORDS[@]}"
    for index in `seq 0 $((${#COMP_WORDS[@]}-1))` ; do
        logger -t "_foo_completion" -- "[$index] ${COMP_WORDS[$index]}"
    done
}
declare -f _foo_completion
complete -F _foo_completion "foo"
alias foo=confirm_args

나는 이것을 요점으로 제공했습니다foo-completion.sh.

복사하여 파일에 붙여넣으세요 /tmp/foo-completion.sh.

두 개의 더미 파일 생성

touch /tmp/a.{1,2}

진단이 제대로 작동하려면 logger시스템 로그를 작성해야 합니다. 그러면 OP는 시스템 로그 파일을 추적하여 진단 출력을 볼 수 있습니다. OP가 실행 중인 경우 systemd새 창을 열고 다음을 입력하여 확인할 수 있습니다.

sudo journalctl -f

라인 완성 및 진단 출력 활성화:

source /tmp/foo-completion.sh

완료가 수행되지 않으므로 _foo_completion후보가 사용자에게 반환되지 않습니다. 행 완성 함수에 어떤 데이터가 전달되었는지 보여주는 것뿐입니다.

일부 입력을 테스트하고 출력을 관찰합니다.

1을 입력하세요

foo a.*[SPACE][TAB]

산출

Jul 23 12:10:34 ub18 _foo_completion[17672]: COMP_CWORD=2
Jul 23 12:10:34 ub18 _foo_completion[17673]: #COMP_WORDS=3
Jul 23 12:10:34 ub18 _foo_completion[17675]: [0] foo
Jul 23 12:10:34 ub18 _foo_completion[17676]: [1] /tmp/a.*
Jul 23 12:10:34 ub18 _foo_completion[17677]: [2]

2를 입력하세요

foo a.*[SPACE][RETURN]

산출

Jul 23 12:19:43 ub18 confirm_args[18487]: #=2
Jul 23 12:19:43 ub18 confirm_args[18489]: [0] bash
Jul 23 12:19:43 ub18 confirm_args[18490]: [1] /tmp/a.1
Jul 23 12:19:43 ub18 confirm_args[18491]: [2] /tmp/a.2

3을 입력하세요

foo a.{1,2}[SPACE][TAB]

산출

참고 - 출력이 없습니다!

4를 입력하세요

foo a.{1,2}[SPACE][RETURN]

산출

Jul 23 12:28:42 ub18 confirm_args[19098]: #=2
Jul 23 12:28:42 ub18 confirm_args[19100]: [0] bash
Jul 23 12:28:42 ub18 confirm_args[19101]: [1] /tmp/a.1
Jul 23 12:28:42 ub18 confirm_args[19102]: [2] /tmp/a.2

분석하다

"INPUT 1"에서는 *리터럴 문자 "*"로 줄 완성 기능에 전달됩니다. 그런데 "INPUT 3"에서는 줄완성 기능도 호출되지 않습니다. 분명히 중괄호로 인해 bash는 줄 완성 기능에 대한 추가 호출을 억제합니다.

반면에 [RETURN] 구문 분석 후 사례에서는2를 입력하세요그리고4를 입력하세요, bash는 두 경우를 모두 확장 a.*하고 a.{1,2}동일한 결과를 얻습니다.

테스트 케이스도 있습니다:

5를 입력하세요

foo a.{[TAB]

산출

Jul 23 12:56:52 ub18 _foo_completion[21059]: COMP_CWORD=1
Jul 23 12:56:52 ub18 _foo_completion[21060]: #COMP_WORDS=2
Jul 23 12:56:52 ub18 _foo_completion[21062]: [0] foo
Jul 23 12:56:52 ub18 _foo_completion[21063]: [1] /tmp/a.{

분석하다

"INPUT 5", bash의 탭 문자 앞에 공백이 없습니다.하다통화 라인이 완료되었습니다. 따라서 이론적으로 행 완성은 단일 후보를 반환할 수 있습니다.

/tmp/a.{1,2}

그러면 자동 완성이 발생합니다(아직 테스트하지는 않았지만).

이것질문그건더 멀리중괄호가 줄 완성을 억제하므로 줄 완성을 사용하여 파일을 추가할 수 없습니다.

기존 줄 완성 기능을 사용하여 테스트합니다.

입력확인

ls /tmp/a.{[TAB][TAB][TAB][TAB][TAB][TAB]

산출

(아무것도 없습니다)

bash가 fancy 이후에 줄 완성을 억제하지 않는 한 줄 완성 기능에서 fancy를 지원할 가치가 없다는 주장을 뒷받침하는 것 같습니다.

[CTRL]{{편집:에 설명된 방법을 사용한 후이 답변, 나는 그것이 완료되었고 (때때로) 더 많은 파일을 추가하기 위해 기본 완성 기능을 따를 수 있다는 것을 발견했습니다. 그러나 이 이후에는 원래 기능을 더 이상 사용할 수 없으며 _foo_completion이는 사용량에 따라 제한이 될 수도 있고 그렇지 않을 수도 있습니다.

관련 정보