多数のファイルを含むディレクトリに対して、Bash のタブ補完を無効にしますか?

多数のファイルを含むディレクトリに対して、Bash のタブ補完を無効にしますか?

私は大量のファイルを扱っており、それらをディレクトリに保存しています。そのディレクトリに移動して誤ってTab2 回押すたびに、パターンに一致するファイルが表示されるまでに時間がかかりすぎます (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設定されたディレクトリの1つに入るときに変数を設定します。変更された補完動作は、その変数が空白でない場合にのみ実行されます。そして空の文字列から補完しようとする場合にのみ、部分的な名前の補完を許可します (-z "$cur"補完を完全に防止するには条件を削除します)。サイレント操作の場合は、2 行をコメント アウトしますprintf

その他のオプションには、必要に応じてディレクトリ内に配置できるディレクトリごとの.noautocompleteフラグ ファイルや、GNU を使用してディレクトリ サイズを推測するオプションがあります。これら 3 つのオプションのいずれか、またはすべてを使用できます。touchstat

stat方法推測に過ぎない報告されたディレクトリ サイズはその内容に応じて大きくなりますが、これは「最高水準点」であり、管理者の介入なしにファイルが削除されても通常は縮小しません。これは、潜在的に大きなディレクトリの実際の内容を決定するよりも安価です。正確な動作とファイルごとの増分は、基礎となるファイルシステムによって異なります。少なくとも Linux ext2/3/4 システムでは、これは信頼できる指標だと思います。

bash は、空の補完が返された場合でも余分なスペースを追加します (これは行末で補完した場合にのみ発生します)。これを防ぐには、コマンド-o nospaceにを追加できます。complete

残る 1 つの問題は、カーソルをトークンの先頭まで戻して Tab キーを押すと、デフォルトの補完が再び開始されることです。これは機能として考えてください ;-)

(あるいは、オーバーエンジニアリングが好きならいじってみるのもいいです${COMP_LINE:$COMP_POINT-1:1}が、コマンドの途中で戻って補完を試みた場合、bash 自体が補完変数を確実に設定できないことがわかりました。)

答え2

dataディレクトリに特定のサフィックスを持つファイルが含まれている場合、例えば .outbash変数FIGNOREを に設定する".out"と、これらは無視されます。ディレクトリ名も使用できますが、これは現在作業中のディレクトリ名には役立ちません。

例:

RAID 1 HDD を搭載した物理ホスト上に 100 KB のテスト ファイルを数千個作成します。

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

単一のタブでは、表示されるまでにほんの一瞬の遅延が発生しますtest.out

テスト場所20万ファイル:

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

答え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
}  

関連情報