Comment faire pour que `cd dir / nom de fichier` m'emmène dans dir /?

10

Je trouverais très pratique de pouvoir l'utiliser cdavec un argument de fichier .

cd myDirectory/anyname.anyExtension serait équivalent à cd myDirectory/

Quel serait le meilleur alias ou la meilleure fonction pour obtenir ce comportement?

EDIT : Désolé, je ne l'ai pas mentionné à la 1ère place: j'utilisezsh

Sébastien
la source

Réponses:

5

Dans zsh, je fais souvent:

cd /path/to/somefile(:h)

( hpour head).

Si somefileest un lien symbolique, vous pouvez également faire:

cd somefile(:A:h)

Pour accéder au répertoire où se trouve la cible du lien symbolique.


L' zshéquivalent de la bashsolution désormais unique de Chris serait:

cd() {
  [[ ! -e $argv[-1] ]] || [[ -d $argv[-1] ]] || argv[-1]=${argv[-1]%/*}
  builtin cd "$@"
}

Dans zsh, vous pouvez également redéfinir ce que les "mots" Ctrl-Wsuppriment.

Dans zsh, les "mots" dans le contexte des widgets de mouvement / transposition / suppression basés sur des mots sont des séquences d'aluns plus les caractères de la $WORDCHARSvariable qui inclut par défaut /.

Vous pouvez supprimer /de $WORDCHARSsorte que Ctrl-Wne supprime qu'un seul composant de chemin:

WORDCHARS=${WORDCHARS/\/}

Une autre extension utile est le select-word-stylewidget que vous pouvez utiliser pour choisir interactivement entre différents styles de mots.

autoload select-word-style
zle -N select-word-style
bindkey '\ew' select-word-style

Une pression sur Alt-Wvous permet de choisir entre différents styles de mots.

$ cd /blah/blih<Alt-W>
Word styles (hit return for more detail):
(b)ash (n)ormal (s)hell (w)hitespace (d)efault (q)uit
(B), (N), (S), (W) as above with subword matching
?
Stéphane Chazelas
la source
Intéressant. (J'utilise aussi zsh).
Sébastien
Édition très intéressante sur la puissance des zshstyles de mots. Merci aussi pour la zshcommande. Il fait parfaitement l'affaire.
Sébastien
15

Je suppose que vous souhaitez toujours conserver la fonctionnalité d'origine si vous entrez un répertoire et que vous l'utilisez bash.

cd() {
    local file="${!#}"

    if (( "$#" )) && ! [[ -d "$file" ]]; then
        builtin cd "${@:1:($#-1)}" "${file%/*}"
    else
        builtin cd "$@"
    fi
}

Si vous n'utilisez jamais les options de cd ( -P, etc.), cela suffira également:

cd() { 
    if [ -d "$1" ] || [ -z "$1" ]; then
        builtin cd "$@"
    else
        builtin cd "${1%/*}"
    fi
}
Chris Down
la source
4
si vous changez le nom de la fonction en cd assurez-vous de l'ajouter builtindevant les cdappels
Ulrich Dangel
@Chris: Vous avez bien compris;) Merci pour cette fonction prête à l'emploi
Sébastien
La version qui conserve les cdoptions ne fonctionne pas avec zsh. Le plus simple fonctionne bien zsh, MAIS cdn'est plus équivalent comme cd ~: /
Sébastien
@Sebastien Essayez maintenant, je pense que cela devrait résoudre ce problème.
Chris Down
@Chris, en effet l'ajout d'une vérification [ -z "$1" ]était suffisant. J'ai accepté la réponse de Stéphane pour lui donner plus de visibilité, car elle semble être la meilleure solution zsh.
Sébastien
7

Vous pouvez utiliser dirnamepour supprimer le nom de fichier du chemin d'accès, par exemple

mycd() { cd "$(dirname "$1")"; }

Tu vois man dirname.

Adrian Frühwirth
la source
3
Notez que si vous entrez un répertoire, cela changera dans le répertoire au - dessus de ce répertoire, ce qui peut ne pas être souhaité (il n'est pas clair de la question de savoir si cela est souhaité ou non).
Chris Down
1
@ChrisDown C'est vrai, mais j'ai laissé cela comme un exercice au lecteur et votre réponse montre comment y faire face.
Adrian Frühwirth
1
@ AdrianFrühwirth Un exercice! Hah!
3

Si vous ajoutez ceci à votre .profile, puis chargez-le ( source ~/.profileou déconnectez-vous et reconnectez-vous), puis vous mycd [file or directory]amènera au bon répertoire:

mycd() { if [ -d "$1" ]; then cd "$1"; else cd "$( dirname "$1" )"; fi ; }

Si vous le nommez cd, des choses étranges se produiront.

jwhitlock
la source
1
Cela se cassera si le nom du répertoire contient des espaces, et vous avez besoin d'un point-virgule de fermeture pour terminer le groupe de commandes. Je l'ai édité pour vous, j'espère que cela ne vous dérange pas.
Chris Down
@ChrisDown, bien que cela soit vrai pour les autres shells, vous n'avez pas besoin du point-virgule de fermeture zsh.
Stéphane Chazelas
En outre, cela se casse si vous passez des arguments à cd, comme -P.
Chris Down
0
cd2() {
 arg=() dir= cmd= IFS=" " msg='[-L|[-P [-e]]|-h] [dir|file]'

 while [ "$#" -gt 1 ] ; do
  case "$1" in
   -h) printf "%s: cd2 %s\n" "$0" "$msg"
    return 1 ;;
   *) arg+=("$1") ;;
  esac
  shift
 done

 [ -f "${1:-}" ] && dir="$(dirname ${1:-})" || dir="${1:A}"
 [ ! -z "$arg" ] && cmd="cd ${arg[@]} $dir" || cmd="cd $dir"

 if ! $cmd 2>/dev/null; then
  printf "%s: cd2 %s\n" "$0" "$msg"
  return 1
 fi
}
ecwpz91
la source
Étant donné un répertoire appelé $(sudo reboot), cette fonction peut redémarrer le système. En outre, l'utilisateur utilise zsh, non bash.
Kusalananda
Donnez n'importe quelle commande $ (sudo reboot), cette fonction redémarrera le système. De plus, +1 je n'ai pas remarqué 'zsh' au début - bonne prise.
ecwpz91
Non, cd '$(sudo reboot)'changerait de répertoire, tandis que votre fonction essaierait d'évaluer le nom.
Kusalananda
Ah, je vois et j'ai fait des changements. Faites-moi savoir si cela fonctionne? Bonne prise.
ecwpz91