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
논리를 난독화하는 경우에는 예상대로 확장되지 않는 경우도 있습니다 .
zsh
Bash 솔루션을 과도하게 엔지니어링하는 대신 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
이는 사용량에 따라 제한이 될 수도 있고 그렇지 않을 수도 있습니다.