많은 수의 파일이 포함된 일부 디렉터리에 대해 Bash에서 탭 완성을 비활성화하시겠습니까?

많은 수의 파일이 포함된 일부 디렉터리에 대해 Bash에서 탭 완성을 비활성화하시겠습니까?

나는 디렉토리에 보관되어 있는 많은 수의 파일로 작업하고 있습니다. 해당 디렉토리에 들어가서 실수로 Tab두 번 누를 때마다 패턴과 일치하는 파일을 표시하는 데 너무 오랜 시간이 걸리며(아마도 1분 이상) 이러한 동작에 상당히 짜증이 납니다.

예를 들어 내 디렉터리 구조는 다음과 같습니다.

my-project/
├── docs/
├── data/        <---- contains around 200k files.
└── analyser/

저는 여전히 완성을 좋아하는데 디렉토리에서만 이 기능을 비활성화할 수 있나요 data/? 5초 동안 시간 제한을 설정하거나 특정 디렉터리에 있을 때 자동으로 완료를 끄는 스크립트와 같은가요?

답변1

이것은 완벽하지는 않지만 bash 완성은 꽤 까다로운 일입니다 ...

가장 간단한 방법은 명령별로 수행하는 것보다 약간 더 유연합니다 FIGNORE. 다음과 같이 할 수 있습니다.

 complete -f -X "/myproject/data/*" vi

이는 vi파일에 대한 완성을 자동 완성하고 필터와 일치하는 패턴을 제거하도록 지시합니다 -X. 단점은 패턴이 정규화되지 않아 ../data변형이 일치하지 않는다는 것입니다.

차선책은 사용자 정의 PROMPT_COMMAND함수일 수 있습니다.

# associative arrays of non-autocomplete directories
declare -A noacdirs=([/myproject/data]=1 )

function _myprompt {
    [[ -n "${noacdirs[$PWD]}" ]] && {
       echo autocomplete off
       bind 'set disable-completion on'
    } || {
       echo autocomplete on
       bind 'set disable-completion off'
    }
} 

PROMPT_COMMAND=_myprompt

이것완료를 비활성화합니다(완전히) 당신이 디렉토리에 있을 때,하지만해당 디렉토리의 파일뿐만 아니라 모든 경로에 대해 비활성화됩니다.

정의된 경로에 대해 이것을 선택적으로 비활성화하는 것이 일반적으로 더 유용할 것이지만, 유일한 방법은 기본 완성 기능(bash-4.1 이상에서 complete -D)을 사용하고 많은 혼란을 겪는 것이라고 생각합니다.

이것~해야 한다당신을 위해 일하지만5월의도하지 않은 부작용이 있습니다(즉, 어떤 경우에는 예상되는 완료가 변경됨).

declare -A noacdirs=([/myproject/data]=1 )

_xcomplete() {
    local cur=${COMP_WORDS[COMP_CWORD]} # the current token

    name=$(readlink -f "${cur:-./}")  # poor man's path canonify
    dirname=$(dirname "$name/.")

    [[ -n "${noacdirs[$dirname]}" ]] && {
        COMPREPLY=( "" )   # dummy to prevent completion
        return
    }
    # let default kick in
    COMPREPLY=()
}

complete -o bashdefault -o default -F _xcomplete vi

이는 을 완료하는 데 사용되며 vi필요에 따라 다른 명령을 추가할 수 있습니다. 경로나 작업 디렉터리에 관계없이 명명된 디렉터리에 있는 파일의 완료를 중지해야 합니다.

나는 일반적인 접근 방식이 complete -D각 명령이 발생할 때마다 완료 기능을 동적으로 추가하는 것이라고 생각합니다. complete -E(입력 버퍼가 비어 있을 때 명령 이름 완성)을 추가해야 할 수도 있습니다 .


업데이트 다음은 완성 기능 솔루션의 하이브리드 버전입니다 PROMPT_COMMAND. 제 생각에는 이해하고 해킹하기가 조금 더 쉽습니다.

declare -A noacdirs=([/myproject/data]=1 [/project2/bigdata]=1)

_xcomplete() {
    local cmd=${COMP_WORDS[0]}
    local cur=${COMP_WORDS[COMP_CWORD]} # the current token

    [[ -z "$cur" && -n "$nocomplete" ]] && {
        printf "\n(restricted completion for $cmd in $nocomplete)\n"  
        printf "$PS2 $COMP_LINE"
        COMPREPLY=( "" )   # dummy to prevent completion
        return
    }
    COMPREPLY=()       # let default kick in
}

function _myprompt {
    nocomplete=
    # uncomment next line for hard-coded list of directories
    [[ -n "${noacdirs[$PWD]}" ]] && nocomplete=$PWD
    # uncomment next line for per-directory ".noautocomplete"
    # [[ -f ./.noautocomplete ]] && nocomplete=$PWD
    # uncomment next line for size-based guessing of large directories
    # [[ $(stat -c %s .) -gt 512*1024 ]] && nocomplete=$PWD
} 

PROMPT_COMMAND=_myprompt
complete -o bashdefault -o default -F _xcomplete vi cp scp diff

이 프롬프트 기능은 nocomplete구성된 디렉터리 중 하나를 입력할 때 변수를 설정합니다. 수정된 완료 동작은 해당 변수가 비어 있지 않은 경우에만 시작됩니다.그리고빈 문자열에서 완성을 시도할 때만 부분 이름의 완성을 허용합니다( -z "$cur"완전히 완료를 방지하려면 조건을 제거하세요). 자동 작동을 위해 두 printf줄을 주석 처리합니다.

다른 옵션에는 필요에 따라 디렉터리에 저장할 .noautocomplete수 있는 디렉터리별 플래그 파일이 포함됩니다 . touchGNU를 사용하여 디렉토리 크기를 추측합니다 stat. 세 가지 옵션 중 일부 또는 전부를 사용할 수 있습니다.

( stat방법단지 추측일 뿐이다, 보고된 디렉터리 크기는 해당 내용과 함께 커지며, 이는 관리자 개입 없이 파일이 삭제될 때 일반적으로 줄어들지 않는 "하이 워터마크"입니다. 잠재적으로 큰 디렉토리의 실제 내용을 결정하는 것보다 저렴합니다. 파일당 정확한 동작과 증분은 기본 파일 시스템에 따라 다릅니다. 적어도 Linux ext2/3/4 시스템에서는 신뢰할 수 있는 지표라고 생각합니다.)

bash는 빈 완성이 반환되는 경우에도 추가 공간을 추가합니다(이는 줄 끝에서 완료할 때만 발생합니다). 이를 방지하기 위해 명령을 -o nospace추가 할 수 있습니다 .complete

한 가지 남은 문제는 커서를 토큰의 시작 부분으로 백업하고 탭을 누르면 기본 완료가 다시 시작된다는 것입니다. 기능이라고 생각하세요 ;-)

(또는 과도한 엔지니어링을 좋아한다면 이리저리 고민할 수도 있지만 ${COMP_LINE:$COMP_POINT-1:1}백업하고 명령 중간에 완료를 시도할 때 bash 자체가 완료 변수를 안정적으로 설정하지 못하는 것을 발견했습니다.)

답변2

data디렉토리에 특정 접미사가 붙은 파일이 포함되어 있는 경우예를 들어 .outbash, 변수를 FIGNORE다음으로 설정할 수 ".out"있으며 이는 무시됩니다. 디렉토리 이름을 사용하는 것도 가능하지만 현재 작업 디렉토리 이름에는 도움이 되지 않습니다.

예:

raid 1 HDD를 사용하여 물리적 호스트에 수천 개의 100KB 테스트 파일을 생성합니다.

for i in {1..200000}; do dd if=/dev/urandom bs=102400 count=1 of=file$i.json; done

변수를 설정합니다 bash:
$ FIGNORE=".json"

테스트 파일을 생성합니다:
$ touch test.out

테스트 장소5,000파일:

$ ls *.json|wc -l
5587
$ vi test.out

vi와 Single 사이에 지연이 나타나지 tab않습니다 test.out.

테스트 장소50,000파일:

$ ls *.json|wc -l
51854
$ vi test.out

단일 탭은 나타나기 전에 몇 초의 지연을 생성합니다 test.out.

테스트 장소200,000파일:

$ ls *.json|wc -l
bash: /bin/ls: Argument list too long
$ ls | awk 'BEGIN {count=0} /.*.json/ {count++} END {print count}'
200000
$ vi test.out

vi와 Single 사이에 1초의 지연이 tab나타 test.out납니다.

참고자료:

man bash에서 발췌

FIGNORE
              A  colon-separated  list  of  suffixes to ignore when performing filename completion (see READLINE below).  A filename whose suffix matches one of the entries in FIGNORE is
              excluded from the list of matched filenames.  A sample value is ".o:~".

답변3

이것이 당신이 원하는 것이라고 생각하세요 (@mr.spuratic에서 일부 코드를 빌림)

이는 전체 경로를 사용하여 TAB을 누르는 것을 막지는 않습니다(예:vim /directory/contains/lots/files<tab><tab>

function cd() {
  builtin cd "$@"
  local NOCOMPLETION=( "/" "/lib" )
  local IS_NOCOMPLETION=0
  for dir in "${NOCOMPLETION[@]}"
  do
    echo $dir
    if [[ $(pwd) == "$dir" ]]
    then
      echo "disable completion"
      bind "set disable-completion on"
      IS_NOCOMPLETION=1
      return
    fi                                                                                                                                                                                              
  done
  if [[ $IS_NOCOMPLETION -eq 0 ]]
  then
    echo "enable completion"
    bind "set disable-completion off"
  fi
}  

관련 정보