7
votes

TCSH et / ou terminal Bash Achèvement avec préfixe racine cachée variable

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 commentaires

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).


5 Réponses :


0
votes

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.


1 commentaires

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.



4
votes

Cela semble être comme si cela pourrait faire ce que vous recherchez: xxx

notes:

  • Je pense que l'une des clés est la Nospace Option
  • Je me sens comme si j'ai réinventé une roue quelque part dans la fonction ci-dessus, éventuellement en n'utilisant pas $ comp_point
  • Vous n'êtes pas (encore, au moins) en utilisant $ prev (qui maintient toujours la valeur "foo" dans ma fonction)
  • la lisibilité et la fonctionnalité peuvent être améliorées en utilisant $ () au lieu de backticks
  • Vous devez utiliser la commande pour empêcher les alias d'exécution et telle: flist = $ (commande LS -1 -D ...
  • J'utilise trouver au lieu de ls car il est mieux adapté à
  • Vous pouvez ajouter la barre oblique à l'aide de -s / avec comp gén au lieu de votre awk commande
  • Vous pouvez utiliser $ cur au lieu de $ termes car vous n'avez pas à dépouiller les espaces, mais j'utilise $ Motor et $ neuf (deux nouvelles variables)
  • Il n'est pas nécessaire d'utiliser xargs echo puisqu'un tableau avec les nouvelles lignes fonctionne bien
  • Je n'ai pas testé cela avec des noms de répertoires ayant des espaces ou des lignes neuves en eux

2 commentaires

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!



1
votes

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 { &quote_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;
}


0 commentaires

0
votes

La solution de base TCSH code> est très facile à mettre en œuvre comme suit:

    complete foo 'C@*@D:/root/sub1/sub2/sub3@'


0 commentaires

1
votes

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"


0 commentaires