Temos mais história para o cd?

Respostas:

31

O comando que você está procurando é pushde popd.

Você pode ver um exemplo de trabalho prático pushde popdde aqui .

mkdir /tmp/dir1
mkdir /tmp/dir2
mkdir /tmp/dir3
mkdir /tmp/dir4

cd /tmp/dir1
pushd .

cd /tmp/dir2
pushd .

cd /tmp/dir3
pushd .

cd /tmp/dir4
pushd .

dirs
/tmp/dir4 /tmp/dir4 /tmp/dir3 /tmp/dir2 /tmp/dir1
Ramesh
fonte
1
Também existe o $OLDPWDcaso de você querer alternar entre dois diretórios usando o mesmo comando, mas não tenho certeza de quão específico é o shell e a distribuição / o kernel.
precisa saber é o seguinte
4
O @ivy_lynx OLDPWDexiste em todos os shells do POSIX, mas é inútil para esta pergunta que pergunta como ir além disso (a pergunta já menciona cd -qual é um atalho para cd "$OLDPWD").
Gilles 'SO- stop be evil'
2
Existe uma razão para você usar em cd /tmp/dir1; pushd . vez de apenas pushd /tmp/dir1?
GnP
@gnp, nenhuma razão específica. Foi retirado apenas do link a que me referi na resposta. pushd /tmp/dir1deve funcionar muito bem.
Ramesh
1
Ok, apenas peguei minha curiosidade. Gostaria de sugerir que você melhore sua resposta com um exemplo real, usando pushde popdpercorrendo uma árvore de diretórios para frente e para trás. Sua resposta já é a correta.
GnP
53

Você não especificou qual shell está usando, portanto, seja uma desculpa para anunciar o zsh.

Sim, temos mais histórico para cd, ou seja cd -2, cd -4etc. Muito conveniente é cd -TAB, especialmente com o sistema de conclusão e as cores ativadas:

Isto é o que eu tenho no .zshrc:

setopt AUTO_PUSHD                  # pushes the old directory onto the stack
setopt PUSHD_MINUS                 # exchange the meanings of '+' and '-'
setopt CDABLE_VARS                 # expand the expression (allows 'cd -2/tmp')
autoload -U compinit && compinit   # load + start completion
zstyle ':completion:*:directory-stack' list-colors '=(#b) #([0-9]#)*( *)==95=38;5;12'

E o resultado:

insira a descrição da imagem aqui

jimmij
fonte
4
bash bash bash bash
Tim
7
OK, não vou excluir esta resposta, talvez seja útil para outras pessoas.
jimmij
23
A menos que a pergunta seja específica bash, esta é uma resposta válida. Não o remova.
liori 26/09/14
E se o OP editar sua pergunta para incluir apenas o bash, essa resposta ainda será válida?
Ooker
3
É importante mencionar que, além disso setopt AUTO_PUSHD, nenhuma das configurações acima é necessária para obter uma pilha de diretórios onipresente com conclusão no estoque zsh. PUSHD_MINUSinverte o sentido de cd +e cd -(uma questão de gosto), CDABLE_VARSé irrelevante para as pilhas de diretórios, e a zstyleinvocação fornecida aqui simplesmente adiciona cor à saída de uma conclusão de pilha de diretórios. No entanto, é necessário inicializar o subsistema de conclusão com autoload -U compinit && compinit.
Wjv 07/04
13

Para responder sua pergunta sobre "mais histórico". Não, o cd -recurso no Bash suporta apenas um único diretório para o qual você pode "virar". Como @Ramesh afirma em sua resposta. Se você deseja um histórico mais longo de diretórios, pode usar pushde popdsalvar um diretório ou retornar ao anterior.

Você também pode ver a lista do que está atualmente na pilha com o dirscomando

Uma explicação detalhada pode ser encontrada nesta resposta intitulada: Como uso os comandos pushd e popd? .

slm
fonte
Eu incluí uma referência da sua resposta. Espero que você não se importe. :)
Ramesh
@Ramesh - não, vá em frente.
slm
8

Você pode instalar e usar o meu utilitário dirhistory para o bash.

Basicamente, é um daemon que coleta alterações de diretório de todos os seus shells e um programa Cdk que exibe o histórico e permite escolher qualquer diretório para o qual alternar (para que você não fique limitado a uma pilha).

cjm
fonte
7

Você tem o histórico que deseja:

cd() {
[ "$((${DIRSTACKMAX##*[!0-9]*}0/10))" -gt 0 ] &&
        set -- "$@" "$DIRSTACK"               &&
        DIRSTACK='pwd -P >&3; command cd'     ||
        { command cd "$@"; return; }
_q()    while   case "$1" in (*\'*) :   ;;      (*)
                ! DIRSTACK="$DIRSTACK '$2$1'"   ;;esac
        do      set -- "${1#*\'}" "$2${1%%\'*}'\''"
        done
while   [ "$#" -gt 1 ]
do      case    ${1:---} in (-|[!-]*|-*[!0-9]*) : ;;
        (*)     eval "  set $((${1#-}+1))"' "${'"$#}\""
                eval '  set -- "$2"'" $2"'
                        set -- "${'"$1"'}" "$1"'
        ;;esac; _q "$1"; shift
done
eval "  DIRSTACK=; $DIRSTACK    &&"'
        _q "$OLDPWD"            &&
        DIRSTACK=$DIRSTACK\ $1
        set "$?" "${DIRSTACK:=$1}"'" $1
"       3>/dev/null
[ "$(($#-1))" -gt "$DIRSTACKMAX" ] &&
        DIRSTACK="${DIRSTACK% \'/*}"
unset -f _q; return "$1"
}

Essa é uma função do shell que deve permitir que qualquer shell compatível com POSIX ofereça um histórico de zshestilo cd. Ele faz todo o seu trabalho sem invocar um único subshell, e acredito que seu fluxo é bastante sólido - parece tratar todos os casos corretamente sob testes moderados.

A função tenta jogar da melhor maneira possível com o ambiente, enquanto ainda conta com a sintaxe totalmente portátil - faz apenas uma suposição e é que a $DIRSTACKvariável de ambiente é sua propriedade a ser usada da maneira que quiser.

Ele canoniza todos os caminhos que ele armazena $DIRSTACKe serializa todos eles entre aspas simples - embora garanta que cada um seja citado e serializado com segurança antes de adicioná-lo ao valor da variável e não deve ter nenhum problema com caracteres especiais de qualquer tipo . Se a $DIRSTACKMAXvariável de ambiente estiver configurada, ela será usada como limite superior para o número de caminhos que ela mantém no histórico; caso contrário, o limite é um.

Se você carregar a função da cdmesma forma normal, mas também poderá fazer isso cd -[num]para voltar ao histórico do diretório de alterações.

O mecanismo principal da função é cdele próprio - e as ${OLD,}PWDvariáveis ​​de ambiente. O POSIX especifica que as cdaltere para cada movimento de caminho - e, portanto, isso apenas usa as variáveis ​​internas do shell e salva os valores pelo tempo que você desejar.

mikeserv
fonte
@ datUser - eu sabia que alguém tinha um dat. você é muito bem
mikeserv
4

O script acd_func.sh faz exatamente o que você descreve. Essencialmente, ele sobrecarrega a cdfunção e permite digitar cd --para obter uma lista dos diretórios visitados anteriormente, a partir dos quais você pode selecionar por número. Acho muito difícil usar o bash sem isso e é a primeira coisa que instalo em um novo sistema.

Nick Edwards
fonte
3

Outros já abordaram algumas soluções interessantes. Algum tempo atrás, criei minha própria solução para um problema relacionado que poderia ser modificado rapidamente para criar um "histórico direto". Eu basicamente queria "rotular" alguns diretórios comumente usados ​​e queria que todos os shells abertos os vissem e persistissem entre as reinicializações.

#dir_labels
#functions to load and retrieve list of dir aliases

function goto_complete {
    unset dir_labels
    declare -A dir_labels
    {
    while read line; do
        ll_pre="${line%% *}"
        ll_dir="${line#* }"
        dir_labels["$ll_pre"]="$ll_dir"
    done
    } < ~/.dir_labels
    unset ll_pre
    unset ll_dir

    local cur possib
    cur="${COMP_WORDS[COMP_CWORD]}"
    possib="${!dir_labels[@]}"
    COMPREPLY=( $(compgen -W "${possib}" -- ${cur}) )
}

complete -F goto_complete goto

function goto {
    unset dir_labels
    declare -A dir_labels
    {
    while read line; do
        ll_pre="${line%% *}"
        ll_dir="${line#* }"
        dir_labels["$ll_pre"]="$ll_dir"
    done
    } < ~/.dir_labels
    unset ll_pre
    unset ll_dir

    if [ $# -gt 0 ]; then
    key="$1"
    else
    key=default
    fi
    target="${dir_labels[$key]}"
    if [ -d "$target" ]; then
    cd "$target"
    echo "goto $key: '$target'"
    else
    echo "directory '$target' does not exist"
    fi
}

function label {
    unset dir_labels
    declare -A dir_labels
    {
    while read line; do
        ll_pre="${line%% *}"
        ll_dir="${line#* }"
        dir_labels["$ll_pre"]="$ll_dir"
    done
    } < ~/.dir_labels
    unset ll_pre
    unset ll_dir

    if [ $# -gt 0 ]; then
    target="$1"
    else
    target="default"
    fi
    dir_labels["$target"]=$PWD
    for i in "${!dir_labels[@]}"; do
    echo "$i ${dir_labels[$i]}"
    done > ~/.dir_labels
}

Basicamente, eu faria apenas label foopara chamar o diretório atual fooe, a partir de qualquer shell, o que goto fooocorreria cddiretamente lá. Argumento vazio: labelcriaria um destino padrão para goto.

Eu não me incomodei em implementar a remoção automática de aliases, mas, caso contrário, ainda estou usando isso de uma forma ligeiramente modificada.

orion
fonte
2

Você pode usar minha função "cd history" em http://fex.belwue.de/fstools/bash.html

Ele lembra todos os diretórios em que você esteve e, com "cdh", você verá uma lista dos últimos 9 diretórios. Basta digitar o número e você estará de volta neste diretório.

Exemplo:

framstag @ wupp: /: cdh
1: / usr / local / bin
2: / var
3: /
4: / tmp / 135_pana / 1280
5: / tmp / 135_pana
6: / tmp / weihnachtsfeier
7: / tmp
8: / local / home / framstag
selecione: 4
framstag @ wupp: / tmp / 135_pana / 1280:

O cdh funciona com o autocd, também conhecido como "cd sem cd": você não precisa digitar cd ou pushd.

Framstag
fonte
2

Gostaria de recomendar minha função estendida 'cd' para você:

https://github.com/dczhu/ltcd

insira a descrição da imagem aqui

Ele fornece os seguintes recursos para facilitar a vida:

  • Lista global de diretórios, que mostra os diretórios visitados recentemente de todas as guias / janelas do terminal.
  • Listagem de diretório local, que é local para a sessão atual do shell.
  • Ambas as listagens oferecem suporte à navegação rápida usando j / k (descer / subir), números e pesquisa de palavras.
  • Salto livre global (por exemplo, "cd dir" ou "cd ar" para ir para / path / to / foo / bar / directory /).
treulz
fonte
Hm, parece promissor. Vou dar uma olhada.
Ddnomad 02/04
1

para o bash , basicamente: em vez de usar o cd pushdpara alterar diretórios, eles são salvos (ou seja, empilhados)

pushd /home; pushd /var; pushd log

Para ver o uso da pilha dirse para facilitar a navegação (para obter os números das "entradas da pilha", use:

dirs -v

Resultado:

me@myhost:/home$ dirs -v
 0  /home
 1  /var
 2  /tmp

Agora utilize esses números com cde ~como:

cd ~1

Mas agora esses números são reorganizados agora e a posição "0" será alterada; portanto, apenas pushdo diretório para a posição superior duas vezes (ou use um manequim na posição 0) como:

me@myhost:/home$ dirs -v
 0  /home
 1  /home
 2  /var
 3  /tmp

agora 1..3 vai ficar ai posição eu li isso em algum lugar mas não sei mais, desculpe por não dar crédito

(para liberar o diretório atual da pilha / excluí-lo do uso do histórico popd)

eli
fonte
1

Veja a função cdh em "Shell Programming, 4e" na página 312. Ele mantém o histórico em uma matriz.

Aqui está uma versão mais avançada: https://drive.google.com/open?id=0B4f-lR6inxQWQ1pPZVpUQ3FSZ2M

Ele armazena o histórico no arquivo CDHISTFILE e permite mudar para o diretório mais recente que contém uma string, por exemplo,

cd -src

Ele se instala sobre o comando cd existente fazendo um alias cd=_cd

user2251295
fonte
1

Só queria adicionar marcas fzf como uma solução possível.

Uma vez instalado, ele fornece os comandos para marcar e pular para adicionar e procurar diretórios marcados (sim, não é exatamente o histórico completo, apenas os marcados por você).

O problema que tenho com o comportamento específico da sessão pushd / popd it, ou seja, eu gostaria de ter a mesma pilha em diferentes sessões do bash, o que é possível para as marcas fzf.

Sebastian Müller
fonte
0

Tentei a resposta que o @mikeserv deu, mas não funcionou muito para mim. Não consegui descobrir como consertá-lo, então apenas escrevi o meu:

cd() {
    # Set the current directory to the 0th history item
    cd_history[0]=$PWD
    if [[ $1 == -h ]]; then
        for i in ${!cd_history[@]}; do
            echo $i: "${cd_history[$i]}"
        done
        return
    elif [[ $1 =~ ^-[0-9]+ ]]; then
        builtin cd "${cd_history[${1//-}]}" || # Remove the argument's dash
        return 
    else
        builtin cd "$@" || return # Bail if cd fails
    fi
    # cd_history = ["", $OLDPWD, cd_history[1:]]
    cd_history=("" "$OLDPWD" "${cd_history[@]:1:${#cd_history[@]}}")
}

Isso também está disponível como GistHub Gist . Para usar isso, basta colar a função no seu .bashrcou similar, e você poderá fazer coisas como cd -5voltar ao último diretório em que esteve. cd -hFornecerá uma visão geral do seu histórico.

saagarjha
fonte