
Bash에서는 M- f및 M-를 사용하여 b커서를 한 단어 앞뒤로 이동할 수 있지만 한 단어를 이동할 수 있는 방법이 있습니까?논쟁앞으로 또는 뒤로? 기본적으로 제공되지 않는 경우 일부 구성에 따라 달라질 수 있습니까?
즉, 아래에 표시된 위치 사이를 이동하기 위해 커서를 이동하고 싶습니다.
cp "foo bar.txt" "/tmp/directory with space"
^ ^ ^
| | |
답변1
나는 당신이 bash를 사용하고 있다는 것을 알고 있으며 당신이 요청한 것이 bash에서 가능하다고 확신하지 않습니다. 제가 보여드릴 내용은 요청된 기능을 ZSH에서 구현하는 방법입니다. (ZSH는 향상된 bash와 약간 비슷합니다. 전환하더라도 여전히 능숙함을 유지해야 합니다.)
ZSH에는 ZSH Line Editor(줄여서 zle)가 있습니다. 이는 bash와 마찬가지로 모든 이동 키를 바인딩 가능한 명령으로 제공합니다. 더 나아가 사용자 정의 명령을 정의하는 기능도 있습니다. 사용자 정의 명령은 위젯으로 변환된 모든 쉘 기능입니다.
이러한 함수는 다른 명령을 실행할 수 있으며 문제와 관련된 여러 변수에 액세스할 수도 있습니다. 제가 이야기할 것들은 다음과 같습니다:
- $BUFFER - 현재 편집 중인 전체 줄입니다.
- $CURSOR - 현재 줄의 삽입 위치입니다.
다음과 같은 다른 방법도 사용할 수 있습니다.
- $LBUFFER - 커서 앞의 모든 것입니다.
- $RBUFFER - 커서 뒤의 모든 내용입니다.
이제 ZSH는 사용자 정의 키 바인드를 제공할 수 있을 뿐만 아니라 변수에 대해 수행할 수 있는 훨씬 더 포괄적인 작업 세트도 제공합니다. 이 문제에서 흥미로운 것 중 하나는 다음과 같습니다.
- z - 쉘 구문 분석을 사용하여 확장 결과를 단어로 분할하여 단어를 찾습니다. 즉, 값의 인용을 고려합니다.
다음과 같이 확장된 $BUFFER를 변수에 직접 할당할 수 있습니다.
line=${(z)BUFFER}
(line은 이제 배열이지만 귀찮게도 이 배열은 bash와 달리 인덱스 1에서 시작합니다!)
이는 글로빙 문자의 확장을 수행하지 않으므로 현재 줄의 실제 인수 배열을 반환합니다. 이것을 갖고 나면 버퍼에 있는 각 단어의 시작점 위치에 관심이 있습니다. 불행하게도 두 단어 사이에 공백이 여러 개 있을 수도 있고 반복되는 단어도 있을 수 있습니다. 이 시점에서 제가 생각할 수 있는 가장 좋은 방법은 고려 중인 각 단어를 현재 버퍼에서 제거하는 것입니다. 다음과 같은 것 :
buffer=$BUFFER
words=${(z)buffer}
for word in $words[@]
do
# doing regular expression matching here,
# so need to quote every special char in $word.
escaped_word=${(q)word}
# Fancy ZSH to the rescue! (q) will quote the special characters in a string.
# Pattern matching like this creates $MBEGIN $MEND and $MATCH, when successful
if [[ ! ${buffer} =~ ${${(q)word}:gs#\\\'#\'#} ]]
then
echo "Something strange happened... no match for current word"
return 1
fi
buffer=${buffer[$MEND,-1]}
done
이제 거의 다 왔습니다! 필요한 것은 어떤 단어가 커서 앞의 마지막 단어인지, 어떤 단어가 커서 뒤의 다음 단어의 시작인지 확인하는 방법입니다.
buffer=$BUFFER
words=${(z)buffer}
index=1
for word in $words[@]
do
if [[ ! ${buffer} =~ ${${(q)word}:gs#\\\'#\'#} ]]
then
echo "Something strange happened... no match for current word"
return 1
fi
old_length=${#buffer}
buffer=${buffer[$MEND,-1]}
new_length=${#buffer}
old_index=$index
index=$(($index + $old_length - $new_length))
if [[ $old_index -lt $CURSOR && $index -ge $CURSOR ]]
then
# $old_index is the start of the last argument.
# you could move back to it.
elif [[ $old_index -le $CURSOR && $index -gt $CURSOR ]]
then
# $index is the start of the next argument.
# you could move forward to it.
fi
# Obviously both of the above conditions could be true, you would
# have to have a way to tell which one you wanted to test - but since
# you will have two widgets (one forward, one back) you can tell quite easily.
done
지금까지 커서가 이동할 적절한 인덱스를 파생하는 방법을 살펴보았습니다. 그러나 커서를 이동하는 방법이나 이러한 기능을 키에 바인딩하는 방법은 보여주지 않았습니다.
$CURSOR 변수는 업데이트될 수 있으며, 그렇게 하면 현재 삽입 지점을 이동할 수 있습니다. 아주 쉽습니다!
함수를 키에 바인딩하려면 먼저 위젯에 바인딩하는 중간 단계가 필요합니다.
zle -N WIDGET_NAME FUNCTION_NAME
그런 다음 위젯을 키에 바인딩할 수 있습니다. 특정 키 식별자를 찾아야 할 수도 있지만 일반적으로 Ctrl-LETTER에 바인딩합니다. 이는 충분히 쉽습니다.
bindkey '^LETTER' WIDGET_NAME
이 모든 것을 종합하여 문제를 해결해 보겠습니다.
function move_word {
local direction=$1
buffer=$BUFFER
words=${(z)buffer}
index=1
old_index=0
for word in $words[@]
do
if [[ ! ${buffer} =~ ${${(q)word}:gs#\\\'#\'#} ]]
then
echo "Something strange happened... no match for current word $word in $buffer"
return 1
fi
old_length=${#buffer}
buffer=${buffer[$MEND,-1]}
new_length=${#buffer}
index=$(($index + $old_length - $new_length))
case "$direction" in
forward)
if [[ $old_index -le $CURSOR && $index -gt $CURSOR ]]
then
CURSOR=$index
return
fi
;;
backward)
if [[ $old_index -lt $CURSOR && $index -ge $CURSOR ]]
then
CURSOR=$old_index
return
fi
;;
esac
old_index=$index
done
case "$direction" in
forward)
CURSOR=${#BUFFER}
;;
backward)
CURSOR=0
;;
esac
}
function move_forward_word {
move_word "forward"
}
function move_backward_word {
move_word "backward"
}
zle -N my_move_backwards move_backward_word
zle -N my_move_forwards move_forward_word
bindkey '^w' my_move_backwards
bindkey '^e' my_move_forwards
내 자신의 테스트에 따르면 이것이 효과가 있는 것 같습니다. 바인딩되는 키를 변경하고 싶을 수도 있습니다. 참고로 다음 줄로 테스트했습니다.
one 'two three' "four five" "'six seven' eight nine" * **/ **/**/*
^ ^ ^ ^ ^ ^ ^ ^
캐럿 사이를 탐색했습니다. 포장되지 않습니다.
답변2
예, man bash에서는 다음을 사용할 수 있다고 나와 있습니다.
shell-forward-word
Move forward to the end of the next word. Words are delimited
by non-quoted shell metacharacters.
shell-backward-word
Move back to the start of the current or previous word. Words
are delimited by non-quoted shell metacharacters.
따옴표로 묶이지 않은 일련의 메타 문자는 인수입니다.
기본적으로 키에 바인딩되어 있다고 말하지 않고 inputrc에 없지만 쉘에서는 각각 CMf 및 CMb에 바인딩되어 있습니다. 그렇지 않은 경우 inputrc에 바인딩하십시오.
"\C-M-f": shell-forward-word
"\C-M-b": shell-backward-word
답변3
Ctrl+ s와 Ctrl+를 사용하여 r명령줄(및 명령 기록)을 통해 앞뒤로 대화식으로 검색(및 이동)합니다. Andreas가 요구하는 것과 정확히 일치하지는 않지만 이러한 대화형 검색 기능을 사용하여 선택한 주장으로 빠르게 이동할 수 있습니다.
bash를 실행하면 bind -P
bash의 모든 내용을 볼 수 있습니다.바인딩 가능한 작업.
다른 커서 이동 옵션에 대한 자세한 내용은 아래 링크를 참조하세요.
https://stackoverflow.com/q/657130