J'essaie de configurer l'achèvement du répertoire dans TCSH et / ou BASH (les deux sont utilisés sur mon site) avec une légère torsion: pour une commande particulière "foo", j'aimerais avoir la fin d'une fonction personnalisée Pour faire correspondre le terme premier /-aLimité à un nœud de sous-arbre réel, puis suivez l'achèvement de l'annuaire normal pour toute conditions successifs. Il s'agit d'une combinaison de CDPath et d'achèvement, ou je suppose qu'une forme d'achèvement du répertoire où le point de départ est contrôlé par le script d'achèvement. Cela fonctionnerait comme suit:
_foo() { local cur prev opts flist COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" # Get all command words so far (omit command [0] element itself), remove spaces terms=`echo ${COMP_WORDS[@]:1} | sed -e 's/ //g'` # Get basenames (with trailing slashes) of matching dirs for completion flist=`ls -1 -d /root/sub1/sub2/sub3/${terms}* 2>/dev/null | sed -e 's#^.*/##' | awk '{print $1 "/"}' | xargs echo` COMPREPLY=( $(compgen -W "${flist}" ${cur}) ) return 0 } complete -F _foo foo
5 Réponses :
Vous pouvez simplement faire un lien symbolique au premier noeud intéressant de l'arbre. Je l'ai fait dans le passé quand je ne pouvais pas être dérangé automatiquement des grands arbres de répertoire. P>
Malheureusement, le "premier nœud intéressant" peut varier considérablement. Au fur et à mesure que les utilisateurs passent du temps dans différentes parties de l'arbre et sautent autour des sous-arbres, il n'ya pas de prédiction que les niveaux qu'ils peuvent ancrer une tentative d'achèvement. À moins que nous lions tous les niveaux (semble encombrant et lourd), je ne suis pas sûr que les liens le résoudront.
Cela semble être comme si cela pourrait faire ce que vous recherchez: notes: p>
Nospace code> Option li>
$ comp_point code> li>
$ prev code> (qui maintient toujours la valeur "foo" dans ma fonction) li>
$ () code> au lieu de backticks li>
code> pour empêcher les alias d'exécution et telle:
flist = $ (commande LS -1 -D ... code> li> li> LI>
trouver code> au lieu de
ls code> car il est mieux adapté à li>
-s / code> avec
comp gén code> au lieu de votre
awk code> commande li>
$ cur code> au lieu de
$ termes code> car vous n'avez pas à dépouiller les espaces, mais j'utilise
$ Motor code > et
$ neuf code> (deux nouvelles variables) li>
xargs echo code> puisqu'un tableau avec les nouvelles lignes fonctionne bien li>
Merci Dennis! C'est très proche de ce que je cherche. Je pourrais peut-être l'utiliser avec quelques modifications, ou peut-être même comme cela. Je verrai si je peux aussi appliquer une méthode similaire à TCSH.
Je pensais que j'étais joli seul pour avoir besoin de scripts d'achèvement complexes :) +1 pour l'effort de code!
Ma solution, qui est certes un marteau de 800 lb, était d'écrire un script Perl pour gérer l'achèvement de la façon dont je le souhaite. en TCSH ...
complete cd 'p|1|`complete_dirs.pl $:1 $cdpath`|/' #!/usr/bin/perl my $pattern = shift @ARGV; my @path = @ARGV; my @list; if ($pattern =~ m!^(/.+/|/)(.*)!) { @list = &search_dir($1,$2,undef); } elsif ($pattern =~ m!(.+/|)(.*)!) { my $dir; foreach $dir ('.',@path) { push(@list,&search_dir("$dir/$1",$2,$1)); } } if (@list) { @list = map { "e_path($_) } @list; print join(' ',@list), "\n"; } sub search_dir { my ($dir,$pattern,$prefix) = @_; my @list; if (opendir(D,$dir)) { my $node; while ($node = readdir(D)) { next if ($node =~ /^\./); next unless ($node =~ /^$pattern/); next unless (-d "$dir$node"); my $actual; if (defined $prefix) { $actual = "$prefix$node"; } elsif ($dir =~ m!/$!) { $actual = "$dir$node"; } else { $actual = "$dir/$node"; } push(@list,$actual); } closedir(D); } return @list; } sub quote_path { my ($string) = @_; $string =~ s!(\s)!\\$1!g; return $string; }
La solution de base TCSH code> est très facile à mettre en œuvre comme suit:
complete foo 'C@*@D:/root/sub1/sub2/sub3@'
Donc, voici une solution TCSH. Ajoute une recherche complète de $ CDPath pour des répertoires d'autocompéquation. La commande complète est la suivante:
#!/bin/tcsh -f set psuf="" set tail="" if ( $1 !~ "*/*" ) then set tail="/$1" else set argsplit=(`echo "$1" | sed -r "s@(.*)(/[^/]*\')@\1 \2@"`) set psuf=$argsplit[1] set tail=$argsplit[2] endif set mycdpath=(. $cdpath) set mod_cdpath=($mycdpath) if ($psuf !~ "") then foreach i (`seq 1 1 $#mycdpath`) set mod_cdpath[$i]="$mycdpath[$i]/$psuf" if ( ! -d $mod_cdpath[$i] ) then set mod_cdpath[$i]="" endif end endif # debug statements #echo "mycdpath = $mycdpath" #echo "mod_cdpath = $mod_cdpath" #echo "tail = $tail" #echo "psuf = $psuf" set matches=(`find -L $mod_cdpath -maxdepth 1 -type d -regex ".*${tail}[^/]*" | sed -r "s@.*(/?${psuf}${tail}[^/]*)\'@\1@" | sort -u`) # prune self matches if ($psuf =~ "") then foreach match (`seq 1 1 $#matches`) set found=0 foreach cdp ($mod_cdpath) if ( -e "${cdp}${matches[$match]}" ) then set found=1; break; endif end if ( $found == 0 ) then set matches[$match]="" else set matches[$match]=`echo "$matches[$match]" | sed -r "s@^/@@"` endif end endif echo "$matches"
La variable de l'environnement CDPath de Bash serait-elle fonctionner pour vous?
J'ai examiné CDPATH, mais cela ne fonctionne pas avec l'achèvement. Vous pouvez "nom de CD", mais pas "Nom du CD ..." J'ai vraiment besoin de l'achèvement.
Je pensais que Bash achèvement (le script supplémentaire rempli de friandises utiles qui naviguent avec Bash sur la plupart des distributions) comprenaient une définition mise à jour de la fin de CD à l'aide de CDPATH.
@Jefromi: Vous avez raison et il semble être capable de faire ce que je pense que Jeremy veut.
Merci pour la pointe, je vais vérifier. Il vaut la peine de mentionner cependant que je dois faire plus que CD; Configuration des environnements spécifiques aux sous-armes à la volée par exemple. J'avais l'habitude d'utiliser une commande personnalisée, mais peut-être que je ne peux que changer de CD d'alias à autre chose (cela peut être trop intrusif).