Como fazer com que `cd dir / filename` me leve para dir /?

10

Eu consideraria muito conveniente poder usar cdcom um argumento de arquivo .

cd myDirectory/anyname.anyExtension seria equivalente a cd myDirectory/

Qual seria o melhor alias ou função para atingir esse comportamento?

EDIT : Desculpe, eu não mencionei em primeiro lugar: eu usozsh

Sébastien
fonte

Respostas:

5

Em zsh, geralmente faço:

cd /path/to/somefile(:h)

( hpara head).

Se somefilefor um link simbólico, você também pode:

cd somefile(:A:h)

Para chegar ao diretório em que o destino do link simbólico pode ser encontrado.


O zshequivalente à bashsolução agora única de Chris seria:

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

Em zsh, você também pode redefinir o que "palavras" Ctrl-Wremove.

Em zsh, "palavras" no contexto dos widgets motion / transpose / delete baseados em palavras são sequências de alnums mais os caracteres na $WORDCHARSvariável que, por padrão, inclui /.

Você pode remover /de $WORDCHARSmodo que Ctrl-Wexclui apenas um componente caminho:

WORDCHARS=${WORDCHARS/\/}

Outra extensão útil é o select-word-stylewidget que você pode usar para escolher interativamente entre diferentes estilos de palavras.

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

Em seguida, pressionar Alt-Wpermite escolher entre diferentes estilos de palavras.

$ 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
fonte
Interessante. (Eu também uso o zsh).
Sébastien
Edição muito interessante sobre o poder zshe estilos de palavras. Obrigado também pelo zshcomando. Faz o trabalho perfeitamente.
Sébastien
15

Presumo que você ainda deseja manter a funcionalidade original se inserir um diretório e estiver usando bash.

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

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

Se você nunca usará as opções do CD ( -P, etc), isso também será suficiente:

cd() { 
    if [ -d "$1" ] || [ -z "$1" ]; then
        builtin cd "$@"
    else
        builtin cd "${1%/*}"
    fi
}
Chris Down
fonte
4
se você alterar o nome da função para cd certifique-se de adicionar builtinna frente das cdchamadas
Ulrich Dangel
@ Chris: Você assumiu direita;) Obrigado por esta pronto para usar a função
Sébastien
A versão que preserva as cdopções não funciona zsh. O mais simples funciona bem zsh, MAS cdnão é mais equivalente a cd ~: /
Sébastien
@ Sebastien Experimente agora, acho que isso deve resolver isso.
22413 Chris Down
@ Chris, na verdade, adicionar uma verificação [ -z "$1" ]foi suficiente. Aceitei a resposta de Stephane para lhe dar mais visibilidade, pois parece ser a melhor solução zsh.
Sébastien
7

Você pode usar dirnamepara remover o nome do arquivo do caminho, por exemplo

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

Veja man dirname.

Adrian Frühwirth
fonte
3
Observe que, se você inserir um diretório, isso mudará para o diretório acima desse diretório, o que pode não ser desejado (não está claro na pergunta se isso é desejado ou não).
21713 Chris Down
1
@ ChrisDown True, mas deixei isso como um exercício para o leitor e sua resposta mostra como lidar com isso.
Adrian Frühwirth
1
@ AdrianFrühwirth Um exercício! Hah!
3

Se você adicionar isso ao seu .profile, carregue-o ( source ~/.profileou efetue logout e logon novamente) e mycd [file or directory]o levará ao diretório certo:

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

Se você escolher cd, coisas estranhas acontecerão.

jwhitlock
fonte
1
Isso será interrompido se o nome do diretório contiver espaço em branco e você precisar de um ponto-e-vírgula para finalizar o grupo de comandos. Editou para você, espero que você não se importe.
21713 Chris Down
@ ChrisDown, embora isso seja verdade para outras conchas, você não precisa do ponto e vírgula final zsh.
Stéphane Chazelas
Além disso, isso é interrompido se você passar argumentos para cd, como -P.
Chris Baixo
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
fonte
Dado um diretório chamado $(sudo reboot), esta função pode reiniciar o sistema. Além disso, o usuário está usando zsh, não bash.
Kusalananda
Dê qualquer comando $ (sudo reboot), esta função irá reiniciar o sistema. Além disso, +1 não notei 'zsh' inicialmente - boa captura.
Ecwpz91
Não, cd '$(sudo reboot)'alteraria o diretório, enquanto sua função tentaria avaliar o nome.
Kusalananda
Ah, eu vejo e fiz mudanças. Deixe-me saber se isso funciona? Boa pegada.
Ecwpz91