Ich arbeite mit einer großen Anzahl von Dateien, die ich in einem Verzeichnis aufbewahre. Jedes Mal, wenn ich in dieses Verzeichnis gehe und versehentlich Tabzweimal drücke, dauert es zu lange (kann über eine Minute dauern), bis Dateien angezeigt werden, die dem Muster entsprechen, und dieses Verhalten ärgert mich ziemlich.
Meine Verzeichnisstruktur ist beispielsweise:
my-project/
├── docs/
├── data/ <---- contains around 200k files.
└── analyser/
Da ich die Vervollständigung immer noch liebe, gibt es eine Möglichkeit, diese Funktion nur im data/
Verzeichnis zu deaktivieren? Zum Beispiel durch Festlegen des Timeouts auf 5 Sekunden oder durch ein Skript, das die Vervollständigung automatisch deaktiviert, wenn man sich in einem bestimmten Verzeichnis befindet?
Antwort1
Das ist nicht perfekt, aber andererseits ist die Bash-Vervollständigung eine ziemlich knifflige Sache ...
Die einfachste Möglichkeit ist, sie auf Befehlsbasis auszuführen. Sie ist etwas flexibler als FIGNORE
. Sie können Folgendes tun:
complete -f -X "/myproject/data/*" vi
Dies weist die Autovervollständigung an, dass die Vervollständigung vi
für Dateien erfolgt und Muster entfernt werden, die dem -X
Filter entsprechen. Der Nachteil besteht darin, dass das Muster nicht normalisiert ist ../data
und daher Variationen nicht übereinstimmen.
Die nächstbeste Lösung könnte eine benutzerdefinierte PROMPT_COMMAND
Funktion sein:
# 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
Dasdeaktiviert die Vervollständigung(komplett) wenn Sie sich im Verzeichnis befinden,AberEs deaktiviert es für jeden Pfad, nicht nur für Dateien in diesem Verzeichnis.
Es wäre grundsätzlich sinnvoller, dies für definierte Pfade selektiv zu deaktivieren, aber ich glaube, die einzige Möglichkeit besteht darin, eine Standardvervollständigungsfunktion (Bash-4.1 und höher mit complete -D
) zu verwenden und viel herumzuspielen.
Dassollenfür Sie arbeiten, aber esMaihaben unbeabsichtigte Nebenwirkungen (d. h. in manchen Fällen Änderungen des erwarteten Abschlusses):
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
Dies funktioniert für die Vervollständigung von vi
, bei Bedarf können weitere Befehle hinzugefügt werden. Es sollte die Vervollständigung für Dateien in den genannten Verzeichnissen unabhängig von Pfad oder Arbeitsverzeichnis stoppen.
Ich glaube, der allgemeine Ansatz complete -D
besteht darin, dynamisch Vervollständigungsfunktionen für jeden Befehl hinzuzufügen, sobald er auftritt. Möglicherweise muss auch Folgendes hinzugefügt werden complete -E
(Vervollständigung des Befehlsnamens, wenn der Eingabepuffer leer ist).
Aktualisieren
Hier ist eine Hybridversion der PROMPT_COMMAND
Lösungen mit der Vervollständigungsfunktion, die meiner Meinung nach etwas einfacher zu verstehen und zu hacken ist:
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
Diese Eingabeaufforderungsfunktion setzt die nocomplete
Variable, wenn Sie eines der konfigurierten Verzeichnisse betreten. Das geänderte Vervollständigungsverhalten tritt nur dann ein, wenn die Variable nicht leer ist.Undnur wenn Sie versuchen, die Vervollständigung aus einer leeren Zeichenfolge vorzunehmen, sodass die Vervollständigung von Teilnamen möglich ist (entfernen Sie die -z "$cur"
Bedingung, um die Vervollständigung vollständig zu verhindern). Kommentieren Sie die beiden printf
Zeilen für den stillen Betrieb aus.
.noautocomplete
Zu den weiteren Optionen gehören eine Flag-Datei pro Verzeichnis , die Sie touch
nach Bedarf in einem Verzeichnis speichern können, und die Schätzung der Verzeichnisgröße mithilfe von GNU stat
. Sie können eine oder alle dieser drei Optionen verwenden.
(Die stat
Methodeist nur eine Vermutung, die gemeldete Verzeichnisgröße wächst mit seinem Inhalt, es handelt sich um eine „Hochwassermarke“, die normalerweise nicht schrumpft, wenn Dateien ohne administratives Eingreifen gelöscht werden. Es ist billiger, als den tatsächlichen Inhalt eines möglicherweise großen Verzeichnisses zu ermitteln. Das genaue Verhalten und die Erhöhung pro Datei hängen vom zugrunde liegenden Dateisystem ab. Ich halte es zumindest auf Linux-Ext2/3/4-Systemen für einen zuverlässigen Indikator.)
bash fügt ein zusätzliches Leerzeichen hinzu, selbst wenn eine leere Vervollständigung zurückgegeben wird (dies tritt nur bei der Vervollständigung am Ende einer Zeile auf). Sie können -o nospace
dem complete
Befehl etwas hinzufügen, um dies zu verhindern.
Ein verbleibender Kritikpunkt ist, dass die Standardvervollständigung wieder aktiviert wird, wenn Sie den Cursor an den Anfang eines Tokens zurücksetzen und die Tabulatortaste drücken. Betrachten Sie es als eine Funktion ;-)
(Oder Sie können ein bisschen herumprobieren, ${COMP_LINE:$COMP_POINT-1:1}
wenn Sie es mit der Technik übertreiben möchten, aber meiner Erfahrung nach gelingt es Bash selbst nicht, die Vervollständigungsvariablen zuverlässig festzulegen, wenn Sie mitten in einem Befehl einen Schritt zurückgehen und die Vervollständigung versuchen.)
Antwort2
Wenn Ihr data
Verzeichnis Dateien mit einer bestimmten Endung enthält,z.B .out
, dann können Sie Ihre bash
Variable FIGNORE
auf setzen ".out"
und diese werden ignoriert. Obwohl es möglich ist, auch Verzeichnisnamen zu verwenden, hilft dies bei aktuellen Arbeitsverzeichnisnamen nicht.
Beispiel:
Erstellen Sie Tausende von 100-KB-Testdateien auf einem physischen Host mit RAID-1-Festplatten:
for i in {1..200000}; do dd if=/dev/urandom bs=102400 count=1 of=file$i.json; done
Legen Sie die bash
Variable fest:
$ FIGNORE=".json"
Erstellen Sie die Testdatei:
$ touch test.out
Testen bei5.000Dateien:
$ ls *.json|wc -l
5587
$ vi test.out
Es tritt keine Verzögerung zwischen dem vi und dem einzelnen tab
davor test.out
auf.
Testen bei50.000Dateien:
$ ls *.json|wc -l
51854
$ vi test.out
Beim Erscheinen einer einzelnen Registerkarte kommt es zu einer Verzögerung von einem Sekundenbruchteil test.out
.
Testen bei200.000Dateien:
$ 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
Verzögerung von 1 Sekunde zwischen dem vi und dem tab
vorherigen Single test.out
.
Verweise:
Auszug aus 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:~".
Antwort3
Ich schätze, das ist, was Sie wollen (habe etwas Code von @mr.spuratic ausgeliehen)
Beachten Sie, dass dies Sie nicht daran hindert, die Tabulatortaste zu drücken und dabei den vollständigen Pfad einzugeben (z. B.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
}