파일 수가 많은 일부 디렉토리에 대해 Bash에서 탭 완성을 비활성화 하시겠습니까?


19

디렉토리에 많은 파일을 가지고 작업하고 있습니다. 해당 디렉토리로 이동하여 실수로 Tab두 번 누를 때마다 패턴과 일치하는 파일을 표시하는 데 시간이 오래 걸릴 수 있습니다 (1 분 이상 걸릴 수 있음).

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

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

여전히 완성을 좋아하기 때문에 data/디렉토리 에서만이 기능을 비활성화 할 수 있습니까? 5 초 동안 시간 초과를 설정하거나 특정 디렉토리 내부에서 자동으로 완료를 끄는 스크립트?


이것을 zsh로 전환 하시겠습니까? (bash에서 가능한지 모르겠습니다. zsh에서는 가능하다는 것을 알고 있지만 쉽지는 않을 것입니다. 확인하지 않았습니다.)
Gilles 'SO- 악의를 멈추십시오

답변:


9

이것은 완벽하지는 않지만 다시 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할 수 touch있는 디렉토리 별 플래그 파일이 있습니다 . GNU를 사용한 디렉토리 크기 추측 stat. 이 세 가지 옵션 중 하나 또는 모두를 사용할 수 있습니다.

(이 stat방법 은 추측에 불과하며 ,보고 된 디렉토리 크기는 내용과 함께 증가합니다. "높은 워터 마크"는 관리 개입없이 파일을 삭제해도 일반적으로 줄어들지 않습니다. 디렉토리. 파일 당 정확한 동작과 증가는 기본 파일 시스템에 달려 있습니다. 리눅스 ext2 / 3 / 4 시스템에서 신뢰할 수있는 지표라고 생각합니다.)

bash는 비어있는 완료가 리턴 될 때에도 추가 공간을 추가합니다 (이는 행 끝에서 완료 할 때만 발생 함). 이를 방지하기 위해 명령에 추가 -o nospace할 수 있습니다 complete.

하나의 남은 문제는 커서를 토큰의 시작 부분에 백업하고 탭을 누르면 기본 완료가 다시 시작된다는 것입니다. 기능을 고려하십시오 ;-)

(또는 ${COMP_LINE:$COMP_POINT-1:1}오버 엔지니어링을 좋아한다면 문제를 해결할 수는 있지만 명령 중간에 백업을 완료하고 완료하려고 할 때 bash 자체가 완료 변수를 안정적으로 설정하지 못한다는 것을 알았습니다.)


6

data디렉토리에 특정 접미사 ( :)가있는 파일이 포함 된 경우 변수 를로 .out설정하면 무시됩니다. 디렉토리 이름도 사용할 수 있지만 현재 작업중인 디렉토리 이름에는 도움이되지 않습니다.bashFIGNORE".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와 싱글 사이에 지연이 없습니다 tab beforetest.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 tabbefore 1 초 지연test.out 나타납니다.

참고 문헌 :

남자 강타의 전직

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:~".

1
~ 100k 파일에 대해 dir을 만들어보십시오. 그럼 $ vi <tab><tab>, 어쨌든 많은 시간이 걸립니다. : \
neizod

여전히 문제를 해결하지 못하면 100k .json파일과이라는 단일 텍스트 파일 이 있다고 가정 하십시오 foo.txt. 켜고 FIGNORE='.json'입력 $ vi <tab>하고 여전히 30 분 정도 기다려야합니다 $ vi foo.txt. --- 실제 시나리오 나는 거 편집하지 않다, 또는 그 디렉토리 내에서 파일 유형을 혼합,하지만 난에 설정 한 경우 FIGNORE와 (실수)를 눌러 탭처럼, 내 키보드가 뭔가의 힌트없이 오랜 시간 동안 동결 될 것입니다 Display all 188275 possibilities? (y or n)말해, 이는 키보드를 다시 넣을 수 있습니다.
neizod

@neizod-죄송합니다. FIGNORE가 디렉토리 수준에서 작동하도록 많은 시나리오를 시도했지만 아무 소용이 없습니다. 사용자 정의 솔루션이 필요하거나 해당 호스트에서 bash 완료를 비활성화하거나 자매 사이트 Gilles에 설명 된 zsh 솔루션을 사용해보십시오.
geedoubleya

죄송합니다. 시스템에서 1 초 밖에 걸리지 않습니다. 내 시스템에서는 약 30 분이 걸립니다. 이 솔루션을 작동시키기 위해 새 PC를 사러 갈 것 같습니다.
neizod

0

이것이 당신이 원하는 것 같아요 (@ 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
}  

pushd/를 잊지 마십시오 popd. 이것은 연관 배열이 아닌 일반 배열 만 사용하므로 bash 3.x에서도 작동합니다.
mr.spuratic
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.