내역을 따라가는 명령줄에 내 코드 조각을 어떻게 넣을 수 있나요?

내역을 따라가는 명령줄에 내 코드 조각을 어떻게 넣을 수 있나요?

다양한 텍스트 파일에 수백 개의 테스트되고 시도된 명령과 조각이 저장되어 있습니다. 재사용해야 할 때는 찾아서 명령줄에 복사하여 붙여넣습니다. 신뢰할 수는 있지만 이는 서투른 접근 방식입니다. 이와 대조적으로, 히스토리 파일에서 이전 명령을 명령줄로 직접 검색하여 편집 및 사용을 위해 준비할 수 있습니다. 이 기능을 에뮬레이션하고 자체 명령 세트를 사용하려면 어떻게 해야 합니까?

fzf를 사용하여 검색하고 내 명령을 찾아서 기록 파일에 추가하는 스크립트가 있습니다. 이것은 훌륭하게 작동합니다. 그러나 그것은 역사적 문서를 혼란스럽게 만듭니다.

이것은 내 스크립트입니다.

find ~ -type f | fzf --preview-window=up:50% --header "ENTER:less; ^s:snip to history" --bind "enter:execute(less {})"  --bind "ctrl-s:execute(cat {} | fzf -m --preview-window=:hidden  >>~/.bash_history)"; history -n

답변1

대화형 Bash를 위한 빠르고 간단한 설정(my bash --versionprint 5.2.15):

  1. 원하는 (한 줄) 명령을 ~/.commands.

  2. 다음 도우미 함수를 정의합니다.

    _get_command () {
       READLINE_LINE="$(<~/.commands fzf -1 --query="$READLINE_LINE")" &&
       READLINE_POINT="${#READLINE_LINE}"
    }
    
  3. 키에 바인딩(키 시퀀스):

    bind -x '"\C-x\C-r":_get_command'
    
  4. Ctrl+ x, Ctrl+ 를 사용하여 시작하세요 r.

노트:

  • READLINE_POINT="${#READLINE_LINE}"커서는 맨 끝에 위치해야 합니다. Bash 5는 문자 길이를 원하고 위 코드는 작동하지만 Bash 4는 바이트를 원합니다. Bash 4에서 ASCII가 아닌 텍스트를 처리하려면 다음을 사용하십시오.

    READLINE_POINT="$(printf '%s' "$READLINE_LINE" | wc -c)"
    

    (나는 -에서왔다이 답변).

  • ~/.commands각 명령에 대해 원하는 커서 위치를 지정하거나 인코딩하기 위해 자신만의 형식을 만들 수 있기 때문입니다 . 귀하의 형식에 따라 설정할 수 있도록 도우미 기능이 향상되었습니다 READLINE_LINE.READLINE_POINT

    반면에 ~/.commands저장 전용 리터럴 명령은 다음과 같습니다.단순한그리고 --query="$READLINE_LINE".

  • 여러 줄 명령의 경우 fzf --read0및 에 null로 끝나는 항목이 필요합니다 ~/.commands. 이 형식을 유지하는 것은 개행 문자로 끝나는 항목을 편집하는 것보다 더 어렵습니다.


위의 내용을 작성한 후 이 기능이 필요하다고 결정했습니다. 더 복잡한 솔루션은 다음과 같습니다 ~/.bashrc.

export SNIPPETFILE

_del_snippet () {
   SNIPPETFILE="${SNIPPETFILE:-"$HOME/.snippets"}"
   printf '%s\0' "$1" | sort -zm -- "$SNIPPETFILE" - | uniq -zu >"$SNIPPETFILE"~ \
   && mv -- "$SNIPPETFILE"~ "$SNIPPETFILE"
   cat -- "$SNIPPETFILE"
}
export -f _del_snippet

_get_snippet () {
   SNIPPETFILE="${SNIPPETFILE:-"$HOME/.snippets"}"
   local line
   line="$(<"$SNIPPETFILE" fzf -1 --read0 --query="$READLINE_LINE" \
      --border top --border-label 'Enter to confirm, Ctrl+y to delete entry, Ctrl+c to abort' \
      --bind 'ctrl-y:reload-sync(exec bash -c "_del_snippet \"\$1\"" bash {})')" \
   && READLINE_LINE="$line" \
   && READLINE_POINT="${#READLINE_LINE}"
}
bind -x '"\C-x\C-r":_get_snippet'

_put_snippet () {
   [[ "$READLINE_LINE" =~ ^[[:space:]]*$ ]] && return 0
   SNIPPETFILE="${SNIPPETFILE:-"$HOME/.snippets"}"
   if
      touch -- "$SNIPPETFILE" \
      && printf '%s\0' "$READLINE_LINE" | sort -zum -- "$SNIPPETFILE" - >"$SNIPPETFILE"~ \
      && mv -- "$SNIPPETFILE"~ "$SNIPPETFILE"
   then
      printf 'command stored in `%s'\''\n' "$SNIPPETFILE" >&2
   else
      printf 'storing in `%s'\'' failed\n' "$SNIPPETFILE" >&2
      return 1
   fi
}
bind -x '"\C-x\C-m":_put_snippet'

용법:

  • Ctrl+ x, Ctrl+를 사용하여 현재 명령줄을 저장합니다 m.

  • Ctrl+ x, Ctrl+를 사용하여 r저장된 명령 목록에서 선택합니다. 이미 입력한 내용과 정확하게 일치하는 항목이 있으면 명령줄로 이동됩니다. 더 많은 경우 대화식으로 선택할 수 있습니다.

  • 대화형으로 선택할 때 Ctrl+는 y강조 표시된 항목을 제거합니다.

노트:

  • 여러 줄 명령이 지원되지만 올바르게 저장하려면 클릭할 수 없습니다 Enter(따옴표 안이나 뒤 \). 그렇지 않으면 보조 프롬프트가 나타납니다. 기록에서 여러 줄 명령을 가져오거나 Ctrl+ v, +를 눌러 Ctrl명령을 여러 줄로 만들어야 j보조 프롬프트가 나타나지 않고 계속 전체 명령을 편집할 수 있습니다. 그런 다음 Ctrl+ x, Ctrl+ 는 m전체 여러 줄 명령을 저장할 수 있습니다.

    이러한 줄을 대화형으로 선택하면 여러 줄 명령처럼 보이지 않지만 여러 줄로 명령줄에 표시됩니다.

    여기에는 좋은 부작용이 있습니다. 레이블이 지정된 명령을 저장할 수 있습니다. 이것

    # description (label) here
    :
    actual_command args
    

    목록은 다음과 같습니다.

    # description (label) here : actual_command args
    

    하지만 선택한 후에는 작동합니다.

  • 기본 파일은 입니다 $HOME/.snippets. export라는 변수를 설정하고 사용하여 다른 경로 이름을 사용할 수 있습니다 SNIPPETFILE. 뒤에 물결표가 있는 경로 이름(예: $HOME/.snippets~)도 유지 관리에 사용됩니다.

  • Bash 5.2.15에서 GNU 및 GNU로 sort테스트되었습니다 uniq(이식 가능하지 않은 옵션 사용).

  • 여전히 오류가 있을 수 있습니다.

답변2

문제를 해결하려면 xdotool을 탐색해 볼 가치가 있습니다.

매뉴얼 페이지에 따르면:

xdotool을 사용하면 키보드 입력 및 마우스 활동을 프로그래밍 방식으로(또는 수동으로) 시뮬레이션하고 창을 이동하고 크기를 조정하는 등의 작업을 수행할 수 있습니다.

따라서 즐겨찾는 명령을 찾는 데 도움이 되는 별칭을 정의하고 xdotool에 이를 명령줄에 배치하도록 지시할 수 있습니다. 예를 들어:

$ alias my_command='stty -echo &&  xdotool type "$(cat any_list | fzf)" ; stty echo'

이렇게 하면 "any_list" 파일에서 텍스트 줄을 추출하여 명령줄에 배치할 수 있습니다. 해당 텍스트가 이전 명령 중 하나인 경우 해당 텍스트를 편집하고 실행할 수 있습니다.

현재 설정에 이미 xdotool이 있을 수 있습니다. 그렇지 않다면 다운로드하고 설치하는 것이 매우 쉽습니다.https://installati.one/install-xdotool-debian-12

답변3

존재하다 bash,shell-expand-line(키보드 단축키 M-C-e, 일반적으로 ++ ALT) 는 "쉘처럼 줄을 확장합니다. 이는 모든 쉘 단어 확장뿐만 아니라 별칭 및 기록 확장도 수행합니다."CTRLe

따라서 원하는 것을 달성하는 가장 쉬운 방법은 명령줄에 삽입하려는 명령을 일부 변수에 할당하고 변수 이름을 쓴 다음 이 키 시퀀스를 눌러 내용을 확장하는 것입니다.

예를 들어:

$ COMMAND="echo hello world"

이제 명령줄에 변수 이름( $COMMAND이 경우) 을 쓰고 ALT+ CTRL+ 를 누르세요 e. $COMMAND현재 줄의 내용으로 자동으로 대체됩니다.

$ echo hello world

$(!!)또는 시퀀스를 작성하고 클릭하여 명령줄을 이전 명령의 출력으로 바꿀 수 있습니다. 예를 들어:

$ grep ps .snippets
ps -fp $$
$ $(!!)

해당 지점에서 ALT+를 클릭하면 명령줄이 명령 출력으로 대체 CTRL됩니다 .egrep

$ ps -fp $$

관련 정보