디렉터리 변경 시 Bash 탭 전체 새로 고침

디렉터리 변경 시 Bash 탭 전체 새로 고침

up내가 있는 디렉토리 위의 지정된 디렉토리로 쉽게 이동할 수 있게 해주는 (내 bashrc의 함수로)라는 명령이 있습니다 . 이 명령은 잘 작동하지만 bash 탭 완성 기능을 추가하면 훨씬 더 유용해집니다. 현재 경로의 디렉터리를 식별하고 완료를 위해 나열하는 완료 스크립트를 작성했습니다. 내가 겪고 있는 문제는 디렉토리를 변경할 때마다 완료 스크립트가 다시 로드되지 않는 것 같아서 여전히 이전 디렉토리에 있는 것처럼 결과가 나온다는 것입니다. 명령 기능을 up추가하여 명령을 수정할 수 있었지만 exec bash임의의 디렉터리 변경 명령으로 이를 수행할 수 있는지 잘 모르겠습니다. exec bashfor while the command is running 을 추가하면 이 작업을 수행할 수 있을 것 같지만 cd이를 수행하는 가장 좋은 방법이 무엇인지 잘 모르겠습니다.

예를 들어:

터미널을 열면 홈 디렉터리에 있습니다.

~$

이것을 입력하면 다음과 같은 결과 up <TAB><TAB>가 나타납니다.

~$ up
username home

여기서 사용자 이름은 내 컴퓨터의 사용자 이름입니다. 그런 다음 CD를 입력 dir1/dir2/하고 다음을 up <TAB><TAB>얻었습니다.

~/dir1/dir2$ up
username home

다시 말하지만, 디렉토리를 변경했지만.

내 완료 스크립트 및 up 스크립트의 코드는 다음과 같습니다.

스크립트를 완성하세요:

#/usr/bin/env bash
LS=$(echo $PWD)
LSARRAY=${LS//\// }
complete -W "$LSARRAY" up

위로 명령(.bashrc에서)

LS=$(echo $PWD)
LSARRAY=(${LS//\// })
i=1
if [[ $LS == *$1/* ]]; then
  FIND=$1
  if [[ $1 == */* ]]; then
    ARR=(${FIND//\// })
    FIND=${ARR[${#ARR[@]}-1]}
  fi
  while [ "${LSARRAY[${#LSARRAY[@]}-$i]}" != "$FIND" ] && [ $i != ${#LSARRAY[@]} ]; do
    cd ../
    i=$(($i+1))
  done
  exec bash
else
  echo "Did not find directory $1"
fi

답변1

다음은 다음을 시도하는 함수 up(프로그래밍 가능 완료 대응 포함)의 대체 구현입니다.

  • 임의의 경로를 사용하십시오(공백 문자 및 개행 문자 포함).
  • 변수를 변경하지 마십시오 IFS. 이는 다음 경우에 유용합니다.올바른 회복;
  • 일부 특수 디렉토리를 명시적으로 처리합니다( .여기서는 ..임의의 방식으로 처리되므로 원하는 대로 코드를 조정해야 할 수도 있습니다).

기능 up:

up () {
  local path=$PWD
  case $1 in
    (''|'..')
      cd ..; return ;;
    (.)
      cd .; return ;;
    (/)
      cd /; return ;;
    (*/*)
      printf '"%s" %s\n' "$1" 'contains forward slashes, up will not work' >&2
      return 1 ;;
  esac
  if [[ $path != /* ]]; then
    printf '%s\n' 'PWD is not an absolute path, up will not work' >&2
    return 1
  fi
  until [[ $path = / ]]; do
    path=${path%/*}
    path=${path:-/}
    if [[ ${path%"$1"} != "$path" ]] # You may add && [[ -d ${path%"$1"} ]] to
                            # make "up oo" fail when you are in `/foo/bar`,
                            # while "up foo" would succeed anyway
    then
      cd -- "$path"
      return
    fi
  done
  printf '%s "%s" %s\n' 'Directory' "$1" 'not found' >&2
  return 1
}

완성 _up기능 및 설명( complete명령):

_up () {
  local cur last path
  declare -A ancestors
  cur=${COMP_WORDS[$COMP_CWORD]}
  path=$PWD
  if [[ $path != /* ]]; then
    return 1
  fi
  until [[ -z $path ]]; do
    path=${path%/*}
    last=${path##*/}
    last=${last:-/}
    if [[ $last == "${cur}"* ]]; then
      ancestors+=( ["$last"]= )
    fi
  done
  COMPREPLY=( "${!ancestors[@]}" )
  return
}
complete -o nospace -o filenames -F _up up

두 코드 조각 모두 에 배치되어야 합니다 .bashrc.배쉬 완료완성 기능과 사양을 또는 에 저장하는 것을 선호할 수도 있습니다 $XDG_DATA_HOME/bash-completion( 자세한 내용은 잉크 페이지의 FAQ 참조).~/.local/share/bash-completion~/.bash_completion

슬래시가 포함된 인수는 의도적으로 제외됩니다. 그렇지 않으면 (제 생각에는) foo/bar주의를 기울여야 하기 때문입니다 foo///bar/./../baz(예: 어떤 형태의 정규화 수행).

연관 배열( declare -A)을 사용하려면 Bash >= 4.0이 필요합니다.

답변2

LS문제는 변수 평가가 LSARRAY한 번만 발생하므로 항상 up완성이 정의된 상위 폴더를 사용하여 명령을 완료한다는 것입니다.PWD

상위 폴더를 동적으로 추출하려면 완성 함수를 만들어야 합니다. 이렇게 하면 실제 전류를 기반으로 up 명령을 완료하려고 할 때 LS마다 및 변수가 평가됩니다 .LSARRAYPWD

_complete_up()
{
  local cur=${COMP_WORDS[COMP_CWORD]}
  local LS=$(echo $PWD)
  local LSARRAY=${LS//\// }
  COMPREPLY=( $(compgen -W "${LSARRAY}" -- $cur) )
  return 0
}

complete -F _complete_up up

답변3

다음을 수행할 수 있습니다.

_up () {
        local oldIFS="$IFS" LS="${PWD%/*}"
        IFS='/
'
        if [ -n "$2" ]; then
                COMPREPLY=($(compgen -W "${LS#/}" "$2"))
        else
                COMPREPLY=(${LS#/})
        fi
        IFS="$oldIFS"
}

complete -F _up up

up () {
        local oldIFS="$IFS" i=1 LSARRAY LS="$PWD" FIND ARR
        IFS='/
'
        LSARRAY=(${PWD#/})
        if [[ $LS == */$1/* ]]; then
                FIND=$1
                while [ "${LSARRAY[${#LSARRAY[@]}-$i]}" != "$FIND" ] && [ $i != ${#LSARRAY[@]} ]; do
                        cd ..
                        i=$(($i+1))
                done
        else
                echo "Did not find directory '$1'"
        fi
        IFS="$oldIFS"
}

주요 문제는 (이전 답변에서 언급했듯이) 완료 가능성이 동적으로 생성되지 않는다는 것입니다.

또한 코드는 디렉터리 이름의 공백과 함께 작동하지 않습니다. 내 것은 디렉토리 이름에 개행 문자를 지원하지 않습니다.

또한 말이 안 되기 때문에 선택 목록에서 현재 디렉터리를 제거했습니다.

디렉터리 이름은 절대 포함될 수 없기 때문에 무엇을 if [[ $1 == */* ]]해야 하는지 이해하지 못해서 제거했습니다.if [[ $FIND == */* ]]/

관련 정보