Как заставить `cd dir / filename` перевести меня в dir /?

10

Мне было бы очень удобно иметь возможность использовать cdс аргументом файла .

cd myDirectory/anyname.anyExtension будет эквивалентно cd myDirectory/

Что было бы лучшим псевдонимом или функцией для достижения этого поведения?

РЕДАКТИРОВАТЬ : Извините, я не упомянул об этом в первую очередь: я используюzsh

Себастьен
источник

Ответы:

5

В zsh, я часто делаю:

cd /path/to/somefile(:h)

( hдля head).

Если somefileэто символическая ссылка, вы также можете сделать:

cd somefile(:A:h)

Чтобы попасть в каталог, где может быть найдена цель символической ссылки.


zshЭквивалент Chris' теперь bash-только решение будет:

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

В zsh, вы также можете переопределить то, что «слова» Ctrl-Wудаляет.

В zsh«словах» в контексте основанных на словах виджетов движения / транспонирования / удаления - последовательности чисел плюс символы в $WORDCHARSпеременной, которая по умолчанию включает в себя /.

Вы можете удалить /из $WORDCHARSтак , что Ctrl-Wудаляет только один компонент пути:

WORDCHARS=${WORDCHARS/\/}

Еще одним полезным расширением является select-word-styleвиджет, который вы можете использовать для интерактивного выбора между различными стилями слов.

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

Затем нажатие Alt-Wпозволяет выбирать между разными стилями слов.

$ 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
?
Стефан Шазелас
источник
Интересно. (Я тоже использую zsh).
Себастьян
Очень интересное редактирование по силе zshи слову стилей. Спасибо также за zshкоманду. Это делает работу отлично.
Себастьян
15

Я предполагаю, что вы все еще хотите сохранить исходную функциональность, если вы вводите каталог, и вы используете bash.

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

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

Если вы никогда не собираетесь использовать опции cd ( -Pи т. Д.), Этого также будет достаточно:

cd() { 
    if [ -d "$1" ] || [ -z "$1" ]; then
        builtin cd "$@"
    else
        builtin cd "${1%/*}"
    fi
}
Крис Даун
источник
4
если вы измените имя функции на cd, убедитесь, что добавили builtinперед cdвызовами
Ulrich Dangel
@Chris: Вы правы;) Спасибо за эту готовую к использованию функцию
Себастьян
Версия, которая сохраняет cdпараметры, не работает с zsh. С более простым работает хорошо zsh, НО cdбольше не эквивалентно так cd ~: /
Себастьян
@Sebastien Попробуйте сейчас, я думаю, это должно исправить это.
Крис Даун
@ Крис, действительно, добавления проверки [ -z "$1" ]было достаточно. Я принял ответ Стефана, чтобы сделать его более заметным, так как это, кажется, лучшее решение для zsh.
Себастьян
7

Вы можете использовать, dirnameчтобы убрать имя файла из пути, например

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

См man dirname.

Адриан Фрювирт
источник
3
Обратите внимание, что если вы введете каталог, он изменится на каталог выше этого каталога, что может быть нежелательно (из вопроса неясно, является ли это желательным или нет).
Крис Даун
1
@ChrisDown Верно, но я оставил это в качестве упражнения для читателя, и ваш ответ показывает, как с этим справиться.
Адриан Фрювирт
1
@ AdrianFrühwirth Упражнение! Хах!
3

Если вы добавите это в свой .profile, затем загрузите его ( source ~/.profileили выйдите из системы и войдите снова), тогда mycd [file or directory]вы попадете в правильный каталог:

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

Если вы назовете это cd, тогда произойдут странные вещи.

jwhitlock
источник
1
Это сломается, если имя каталога содержит пробелы, и вам нужна закрывающая точка с запятой для завершения группы команд. Отредактировал это для вас, надеюсь, вы не возражаете.
Крис Даун
@ChrisDown, хотя это верно и для других оболочек, вам не нужна заключительная точка с запятой zsh.
Стефан Шазелас
Кроме того, это нарушается, если передать аргументы cd, вроде -P.
Крис Даун
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
источник
Если указан каталог $(sudo reboot), эта функция может перезагрузить систему. Кроме того, пользователь использует zsh, а не bash.
Кусалананда
Дайте любую команду $ (перезагрузка sudo), эта функция перезагрузит систему. Кроме того, +1 я изначально не заметил 'zsh' - хороший улов.
ecwpz91
Нет, cd '$(sudo reboot)'изменится каталог, а ваша функция попытается оценить имя.
Кусалананда
Ах, я вижу и внес изменения. Дай мне знать, если это работает? Хороший улов.
ecwpz91