¿Tenemos más historia para cd?

Respuestas:

31

El comando que está buscando es pushdy popd.

Puede ver un ejemplo práctico de trabajo desde pushdy popddesde aquí .

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
fuente
1
También hay $OLDPWDen caso de que desee alternar entre dos directorios con el mismo comando, pero no estoy seguro de cómo es esto específico de shell y de distribución / kernel.
mechalynx
44
@ivy_lynx OLDPWDexiste en todos los shells POSIX, pero es inútil para esta pregunta que pregunta cómo ir más allá (la pregunta ya menciona cd -cuál es un atajo para cd "$OLDPWD").
Gilles 'SO- deja de ser malvado'
2
¿Hay alguna razón que usas en cd /tmp/dir1; pushd . lugar de solo pushd /tmp/dir1?
GnP
@gnp, no hay razón específica. Fue tomado del enlace al que me he referido en la respuesta. pushd /tmp/dir1debería funcionar bien.
Ramesh
1
Ok, acabo de recoger mi curiosidad. Me gustaría sugerirle que mejore su respuesta con un ejemplo real usando pushdy popdpara recorrer un árbol de directorios de un lado a otro. Tu respuesta ya es la correcta.
GnP
54

No especificó qué shell está utilizando, así que deje que esto sea una excusa para anunciar zsh.

Sí, tenemos más historial para cd, a saber cd -2, cd -4etc. Es muy conveniente cd -TAB, especialmente con el sistema de terminación y los colores habilitados:

Esto es lo que tengo en .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'

Y el resultado:

ingrese la descripción de la imagen aquí

jimmij
fuente
44
bash bash bash bash
Tim
77
OK, no borraré esta respuesta, tal vez sea útil para otros.
jimmij
23
A menos que la pregunta pregunte específicamente bash, esta es una respuesta válida. No lo quites.
liori
¿Qué pasa si el OP edita su pregunta para incluir solo bash, esta respuesta seguirá siendo válida?
Ooker
3
Cabe mencionar que, aparte de setopt AUTO_PUSHD, no se requiere ninguna de las configuraciones anteriores para obtener una pila de directorios omnipresente con finalización en stock zsh. PUSHD_MINUSinvierte el sentido de cd +y cd -(una cuestión de gustos), CDABLE_VARSes irrelevante para las pilas de directorios, y la zstyleinvocación dada aquí simplemente agrega color a la salida de la finalización de una pila de directorios. Sin embargo, se debe inicializar el subsistema de finalización con autoload -U compinit && compinit.
wjv
13

Para responder a su pregunta sobre "más historia". No, la cd -función en Bash solo admite un único directorio al que puede "voltear". Como @Ramesh afirma en su respuesta. Si desea un historial más largo de directorios, puede usar pushdy popdguardar un directorio o volver a uno anterior.

También puede ver la lista de lo que está actualmente en la pila con el dirscomando.

Se puede encontrar una explicación detallada de esta respuesta titulada: ¿Cómo uso los comandos pushd y popd? .

slm
fuente
He incluido una referencia de su respuesta. Espero que no te importe. :)
Ramesh
@Ramesh - no, adelante.
slm
8

Puede instalar y usar mi utilidad dirhistory para bash.

Básicamente, es un demonio que recopila cambios de directorio de todos sus shells, y un programa Cdk que muestra el historial y le permite elegir cualquier directorio para cambiar (por lo que no está limitado a una pila).

cjm
fuente
7

Tienes tanta historia como quieras:

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"
}

Esa es una función de shell que debería permitir que cualquier shell compatible con POSIX ofrezca un historial de zshestilo cd. Hace todo su trabajo sin invocar una sola subshell, y creo que su flujo es bastante sólido: parece manejar todos los casos correctamente bajo pruebas moderadas.

La función intenta jugar tan bien con su entorno como puede mientras sigue confiando en una sintaxis totalmente portátil: solo hace una suposición y es que la $DIRSTACKvariable de entorno es su propiedad para hacer lo que quiera.

Canonicaliza todas las rutas que almacena $DIRSTACKy las serializa en comillas simples, aunque garantiza que cada una se cite y serialice de forma segura antes de agregarla al valor de la variable y no debería tener ningún problema con ningún carácter especial de ningún tipo . Si se establece la $DIRSTACKMAXvariable de entorno, la usará como límite superior para el número de rutas que conserva en el historial; de lo contrario, el límite es uno.

Si carga la función de la cdforma habitual, pero también podrá hacer el cd -[num]retroceso a través de su historial de cambio de directorio.

El mecanismo principal de la función es en cdsí mismo, y las ${OLD,}PWDvariables de entorno. POSIX especifica que cdcambien estos para cada movimiento de ruta, por lo que esto solo usa las variables integradas del shell y guarda los valores durante el tiempo que desee.

mikeserv
fuente
@datUser: sabía que alguien tenía un dat. de
nada
4

El script acd_func.sh hace exactamente lo que usted describe. Básicamente, sobrecarga la cdfunción y le permite escribir cd --para obtener una lista de los directorios visitados anteriormente, de los cuales puede seleccionar por número. Me resulta muy difícil usar bash sin esto, y es lo primero que instalo en un nuevo sistema.

Nick Edwards
fuente
3

Otros ya cubrieron algunas soluciones interesantes. Hace algún tiempo, creé mi propia solución a un problema relacionado que podría modificarse rápidamente para hacer un "historial directo". Básicamente quería "etiquetar" algunos directorios de uso común, y quería que todos los shells abiertos los vieran, y que persistieran entre reinicios.

#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
}

Básicamente, simplemente haría label foopara llamar al directorio actual foo, y luego desde cualquier shell, goto foodebería estar cddirectamente allí. Argumento vacío: labelcrearía un objetivo predeterminado para goto.

No me molesté en implementar la eliminación automática de alias, pero de lo contrario, todavía estoy usando esto en una forma ligeramente modificada.

Orión
fuente
2

Puede usar mi función "historial de cd" en http://fex.belwue.de/fstools/bash.html

Recuerda cada directorio donde ha estado y con "cdh" verá una lista de los últimos 9 directorios. Simplemente ingrese el número y regresará a este directorio.

Ejemplo:

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 / hogar / framstag
seleccione: 4
framstag @ wupp: / tmp / 135_pana / 1280:

cdh funciona con autocd, también conocido como "cd sin cd": no tiene que escribir cd o pushd.

Framstag
fuente
2

Me gustaría recomendarle mi función 'cd' extendida:

https://github.com/dczhu/ltcd

ingrese la descripción de la imagen aquí

Proporciona las siguientes características para facilitarle la vida:

  • Listado global de directorios, que muestra los directorios visitados recientemente desde todas las pestañas / ventanas de terminal.
  • Listado de directorio local, que es local para la sesión de shell actual.
  • Ambos listados admiten navegación rápida mediante el uso de j / k (subir / bajar), números y búsqueda de palabras.
  • Salto libre global (por ejemplo, "cd dir" o "cd ar" para ir a / path / to / foo / bar / directory /).
treulz
fuente
Hm, parece prometedor. Lo comprobaré.
ddnomad
1

para bash , básicamente: en lugar de usar el uso de cd pushdpara cambiar los directores, entonces se guardan (lo que significa apilado)

pushd /home; pushd /var; pushd log

Para ver el uso de la pila dirsy para una navegación más fácil (para obtener los números de las "entradas de pila", use:

dirs -v

Salida:

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

Ahora utilice estos números con cdy ~como:

cd ~1

Pero ahora estos números se reordenan y la posición "0" cambiará, por lo que solo pushdel directorio a la posición superior dos veces (o use un ficticio en la posición 0) como:

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

ahora 1..3 mantendrá su posición . Leí esto en alguna parte pero ya no lo sé, así que lo siento por no dar crédito

(para liberar el directorio actual de la pila / eliminarlo del uso del historial popd)

eli
fuente
1

Consulte la función cdh en "Programación de Shell, 4e" en la página 312. Mantiene el historial en una matriz.

Aquí hay una versión más avanzada: https://drive.google.com/open?id=0B4f-lR6inxQWQ1pPZVpUQ3FSZ2M

Almacena el historial en el archivo CDHISTFILE y permite cambiar al directorio más reciente que contiene una cadena, por ejemplo,

cd -src

Se instala sobre el comando cd existente haciendo un alias cd=_cd

usuario2251295
fuente
1

Solo quería agregar marcas fzf como una posible solución.

Una vez instalado, le da a los comandos marcar y saltar para agregar y buscar directorios marcados (sí, no es exactamente el historial completo, solo los que marcó usted mismo).

El problema que tengo con el comportamiento específico de la sesión pushd / popd, es decir, me gustaría tener la misma pila en diferentes sesiones de bash o algo así, que es posible para las marcas fzf.

Sebastian Müller
fuente
0

Intenté la respuesta que dio @mikeserv, pero no funcionó para mí. No sabía cómo solucionarlo, así que escribí el mío:

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[@]}}")
}

Esto también está disponible como GitHub Gist . Para utilizarlo, basta con pegar la función en su .bashrco similares, y usted será capaz de hacer cosas como cd -5ir de nuevo a la 5 ª último directorio que has estado en. cd -hLe dará una visión general de su historia.

saagarjha
fuente