Bash에서 Emacs 스타일 키 바인딩의 혼란스러운 동작

Bash에서 Emacs 스타일 키 바인딩의 혼란스러운 동작

emacs-style keybindingsBash는 유용하고 간단한 명령줄 편집 기능을 많이 제공합니다 . 예를 들어 Ctrl+w커서 왼쪽에 있는 단어를 삭제("kill")합니다.

다른 키 바인딩은 Alt+d첫 번째 키 바인딩의 "미러"여야 합니다. 커서에서 단어를 삭제해야 합니다.

그러나 나는 이 두 키 바인딩의 동작이 완전히 대칭적이지 않다는 것을 발견했습니다. 한 단어 Ctrl+w로 처리 하지 말고 두 단어로 처리하세요.foo.barAlt+d

더 짜증나는 건 # echo두 단어인데 Ctrl+w한 단어라는 점이다 Alt+d.

이것에 논리가 있습니까? 그들이 단어를 같은 방식으로 취급하지 않는 이유가 있습니까?

이것을 바꿀 수 있는 방법이 있나요?

나는 배쉬를 사용하고 있습니다Debian Wheezy

답변1

다른 bash 명령은 다른 단어 개념을 사용합니다. 명령의 각 명령에 대한 설명 보기수동.

C-w이전 공백을 죽입니다. M-DEL(보통 Alt+ ) 단어에 문자와 숫자만 포함된 이전 단어 경계( BackSpace및 와 동일)를 삭제하고 유사하게 앞으로 삭제합니다.M-bM-fM-d

Bash는 Readline 라이브러리를 사용하여 사용자 입력을 처리하며 다음과 같은 방식으로 구성할 수 있습니다.~/.inputrc또는 통해bind내장되어 있습니다 ~/.bashrc. 하나의 키를 다른 키에 바인딩할 수 있습니다.라인 명령 읽기당신이 원하는 경우. 키를 수정된 변수 bind -x에 바인딩하는 bash 함수를 사용할 수도 있습니다 .READLINE_LINE

M-d예를 들어, Kill 단어를 쉘 단어로 만들려면 다음과 같이 바인딩하십시오.shell-kill-word당신의 .bashrc:

bind '"\M-d": shell-kill-word'

공백으로 구분된 단어를 제거 하려면 M-d내장된 함수가 없으므로 매크로나 쉘 함수를 작성해야 합니다. 공백으로 구분된 단어로 이루어진 이동 명령이 없기 때문에 최소한 그 부분은 기능이 필요합니다.

delete_whitespace_word () {
  local suffix="${READLINE_LINE:$READLINE_POINT}"
  if [[ $suffix =~ ^[[:space:]]*[^[:space:]]+ ]]; then
    local -i s=READLINE_POINT+${#BASH_REMATCH[0]}
    READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}${READLINE_LINE:$s}"
  fi
}
bind -x '"\ed": delete_whitespace_word'

M-d내가 아는 한 bash 코드에서 kill 루프에 액세스할 수 있는 방법이 없기 때문에 kill을 공백으로 구분된 단어로 만드는 것은 더 복잡합니다. 따라서 이를 위해서는 삭제할 섹션의 끝을 찾는 함수와 실제 삭제를 따르는 매크로가 필요합니다.

forward_whitespace_word () {
  local suffix="${READLINE_LINE:$READLINE_POINT}" 
  if [[ $suffix =~ ^[[:space:]]*[^[:space:]]+ ]]; then
    ((READLINE_POINT += ${#BASH_REMATCH[0]}))
  else
    READLINE_POINT=${#READLINE_LINE}
  fi
}
bind -x '"\C-xF": forward_whitespace_word'
bind '"\C-x\C-w": kill-region'
bind '"\ed": "\e \C-xF\C-x\C-w"'

이 모든 것이 zsh에서는 훨씬 쉽습니다.

답변2

Readline에는 단어 경계로 공백을 사용하는 vi-fwordand가 이미 있으므로 Gilles의 기능은 필요하지 않습니다.vi-bwordforward_whitespace_word

vi-fword뒤에 unix-word-rubout( \C-w)가 있으면 공백으로 구분된 단어를 뒤로 제거합니다(후행 공백 포함).

bind '"\eb":vi-bword'
bind '"\ef":vi-fword'
bind '"\ed":"\ef\C-w"'

vi-backward-word예 별칭 vi-bword, vi-forward-word예 별칭 vi-fword, vi-backward-bigword예 별칭 vi-bWord, vi-forward-bigword예 별칭 vi-fWord.

답변3

방법의 결과입니다독서선"단어"를 다루십시오. Altd다음의 단축키는 다음과 같습니다 kill-word.

현재 단어의 끝에서 종료되거나, 단어 사이인 경우 다음 단어의 끝까지 종료됩니다.단어 경계는 Mf에서 사용되는 것과 동일합니다.(앞으로 단어).

의 단어 경계는 forward-word다음과 같이 정의됩니다.

단어는 문자와 숫자로 구성됩니다.

대신Ctrlw 바로 가기 unix-word-rubout:

점 뒤의 단어를 죽여라.공백을 단어 경계로 사용.

따라서 예를 사용하기 위해 foo.bar첫 번째 명령은 문자열을 로 구분된 두 개의 "단어"로 처리하는 .반면, 두 번째 명령은 공백을 확인하지 않으므로 단일 "단어"로 처리합니다.

관련 정보