파일 수가 많은 특정 디렉터리에 대해 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)을 사용하는 것이며 많은 혼란을 야기합니다.

이것~해야 한다당신에게는 효과가 있지만가능한예상치 못한 부작용이 있습니다(예: 일부 경우 예상 완료가 변경됨).

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플래그 파일 과 GNU를 사용하여 디렉토리 크기를 추측하는 기능이 포함됩니다 . 이 세 가지 옵션 중 일부 또는 전부를 사용할 수 있습니다.touchstat

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

빈 완성이 반환되더라도 bash는 추가 공백을 추가합니다(이는 줄 끝 완성에서만 발생합니다). 이런 일이 발생하지 않도록 -o nospace명령을 추가할 수 있습니다 .complete

남은 사소한 문제는 커서를 마크업의 시작 부분으로 다시 이동하고 Tab을 누르면 기본 완성이 다시 시작된다는 것입니다. 기능이라고 생각하세요 ;-)

(또는 과도한 엔지니어링을 좋아한다면 자유롭게 사용할 수 있지만 ${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 tabbefore 사이에는 test.out지연이 없습니다 .

테스트 대상50,000문서:

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

개별 탭이 표시되기까지 몇 분의 1초 정도의 지연이 발생합니다 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

tabvi 와 Single 사이에는 1초의 지연이 있습니다 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에서 일부 코드를 빌림)

전체 경로(예: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
}  

관련 정보