it-swarm-pt.com

aliasing cd para pushd - é uma boa ideia?

É uma boa ideia usar o seguinte alias:

cd() {
    pushd $1;
}

em bash?

Acho que isso seria muito útil, já que posso usar uma série de popds em vez de apenas um cd - uma vez.

Existe algum caso em que isso possa ser um problema?

37
Lazer

Pessoalmente, tenho estes em meu bashrc e os uso o tempo todo:

pushd()
{
  if [ $# -eq 0 ]; then
    DIR="${HOME}"
  else
    DIR="$1"
  fi

  builtin pushd "${DIR}" > /dev/null
  echo -n "DIRSTACK: "
  dirs
}

pushd_builtin()
{
  builtin pushd > /dev/null
  echo -n "DIRSTACK: "
  dirs
}

popd()
{
  builtin popd > /dev/null
  echo -n "DIRSTACK: "
  dirs
}

alias cd='pushd'
alias back='popd'
alias flip='pushd_builtin'

Você pode navegar na linha de comando um pouco como um navegador. cd muda o diretório. back vai para o diretório anterior de onde você cded. E flip moverá entre os diretórios atual e anterior sem retirá-los da pilha de diretórios. No geral, funciona muito bem.

O único problema real de que estou ciente é o fato de que é um conjunto de comandos aos quais estou completamente acostumado, mas que não existe na máquina de ninguém. Então, se eu tiver que usar a máquina de outra pessoa, pode ser um pouco frustrante. Se você está acostumado a usar apenas pushd e popd diretamente, você não tem esse problema. E embora se você apenas alias cd put not popd, você não terá o problema de back não existir, você ainda terá o problema de cd não faz exatamente o que você espera em outras máquinas.

Eu observaria, no entanto, que sua implementação particular de cd não funciona exatamente como cd em que o cd normal por si só irá para seu diretório inicial, mas o seu não. A versão que tenho aqui não tem esse problema. O meu também anexa DIRSTACK na frente da impressão dirs, mas isso é mais uma questão de gosto pessoal do que qualquer coisa.

Então, como eu disse, eu uso esses apelidos o tempo todo e não tenho nenhum problema com eles. É que pode ser um pouco frustrante ter que usar outra máquina e depois descobrir que não está lá (o que não deve ser surpreendente, mas é uma daquelas coisas que você usa com tanta frequência que nem pensa nelas , então ainda pode ser surpreendente que eles não funcionem como você está acostumado).

41
Jonathan M Davis

Esta não é uma resposta direta à pergunta, mas me apaixonei pela janela de histórico de diretórios em 4DOS. Tanto é que escrevi minha própria versão para Linux (e Cygwin). Nunca tive a chance de torná-lo um utilitário fácil de instalar, mas se você sabe como lidar com um Bash Prompt, não deveria ser que difícil de conseguir correr. Sua pergunta me inspirou a colocá-lo em um repositório Git e enviá-lo para o GitHub: dirhistory .

Basicamente, é um daemon que coleta mudanças de diretório de todos os seus shells, e um programa Cdk que exibe o histórico e permite que você escolha qualquer diretório para o qual alternar (para que você não esteja limitado a uma pilha). Acho que é realmente útil e vinculado a Ctrl-PageUp, assim como 4DOS fez. (Eu até fiz um patch do PuTTY para enviar Ctrl-PageUp para o Bash.)

7
cjm

Para mim, pushd/popd/dirs é quase útil, mas falta. Então, criei um 'wrapper' em torno deles chamado 'navd', implementado essencialmente como um conjunto de 20 aliases. (Um deles é uma função, na verdade.) O código está abaixo, mas aqui está uma breve explicação primeiro. (Uma coisa boa sobre "navd" e trabalhar em máquinas de outras pessoas: existe uma forma "sem instalação" de executá-lo: como uma opção de instalação, você pode simplesmente colar os comandos que implementam "navd" no prompt bash , e durante a sessão bash para essa máquina, o navd funcionará. Isso dá uma pegada zero no sistema de arquivos, mas é uma instalação temporária. Coloque esses comandos em .bashrc para uma instalação "real" de curso.)

Recursos:

navd <path>;   -- will make that path the current dir AND will add it to the stack
                         AS A BONUS: If a relative path is used, this command is added to history
                         with an absolute path instead. This improves navigation even when only
                         using history ... because very often relative-path commands in history
                         are useless if the command changes the current directory. (After all, you
                         would have to be in the directory the command was originally issued
                         from in order for such a command to work correctly.)
navd           -- shows the stack, with index numbers for convenience
navd0          -- makes the first entry on the stack (read left-to-right) **the current dir**
navd1          -- makes the second entry on the stack (read left-to-right) **the current dir**
.
.
.
navd9          -- makes the tenth entry on the stack (read left-to-right) **the current dir**
navd-1         -- makes the first entry on the stack WHEN READ RIGHT-to-LEFT(!) **the current dir**
.                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
.
.
navd-9         -- makes the 9th entry on the stack WHEN READ RIGHT-to-LEFT(!) **the current dir**

Qualquer um dos dezenove comandos navd <N> gira a pilha para que o diretório que se torna o dir atual também agora seja exibido na frente da pilha. Valores <N> positivos encontram um dir contando a partir da esquerda, com indexação começando em zero. Valores <N> negativos encontram um dir contando da DIREITA, com indexação começando em -1. (Isso segue a convenção de como os índices de matriz podem ser usados ​​em Java e outras linguagens).

Nota: Qualquer comando "navd" exibe a mesma pilha que "pushd" e "dirs" usa - mas exibe SEM a entrada mais à esquerda que "dirs" seria exibido (já que essa entrada não está realmente na pilha - é o diretório atual e com "dirs" que entrada mais à esquerda muda se um comando cd for inserido). (O comando "cd <path>" não afeta nenhum comportamento do navd embora certamente afete o comportamento de pushd/dirs/popd. Além disso ... eu adoro usar "cd -" para volte " uma vez para um diretório de onde acabei de navegar e" cd - "também não afeta o comportamento do navd.)

Bônus: Pode haver mais 19 aliases que NÃO giram a pilha, mas apenas mudam o dir para o local indicado na pilha.

 nav0 ... nav9   and   nav-1  ... nav-9

2º Bônus: "navh" mostra os comandos navd <path> do histórico, para carregar facilmente a pilha com recortar e colar. (Cada um é listado apenas uma vez, mesmo se estiver no histórico várias vezes, e a lista é classificada. Além disso, as entradas podem ser colocadas em um arquivo $ HOME/.navhignore para evitar que as entradas exatas apareçam na lista navh.)

 navh

Três comportamentos principais:

  1. Se você limpar a pilha e repetir um comando específico "navd <path>", esse caminho irá para a pilha. Isso é o que eu quero e espero ... mas pushd não faz isso - ele coloca o diretório atual do qual você está navegando LONGE da pilha - então o efeito na pilha é variável (parece imprevisível) quando você repete o comando .

  2. "navd <path>" não colocará o mesmo caminho na pilha duas vezes.

  3. "navd <path>" se coloca no histórico de comandos com o caminho absoluto , mesmo se o relativo o caminho foi digitado para o comando.

Para mim, os três últimos comportamentos descritos tornam o uso de um comando "navd <path>" do histórico muito mais útil do que o uso de um "pushd <path>" do histórico. Eu realmente posso reutilizar a história para ir a lugares. E quando faço isso, não "estrago" minha pilha.

Se você puder e quiser envolver seu cérebro em torno disso, pode alternar entre o uso de navd e pushd/dirs/popd. Ambos usam a mesma pilha; apenas com um estilo diferente. Por exemplo, use "popd" para remover coisas da pilha "navd" ou use "dirs -c" para limpar a pilha navd.

Pense em pushd/dirs/popd como "como faço para refazer meus passos?".
Pense em navd como "como faço para manter um conjunto de diretórios favoritos e alternar facilmente entre eles?".

Cole o seguinte em uma janela de terminal e você pode começar a usar navd imediatamente durante essa sessão de terminal. Este é todo o código que existe para este recurso.

# Add 1 function and many related aliases for something like "pushd", called "navd". http://unix.stackexchange.com/a/229161
# Think of pushd/dirs/popd as "how do I retrace my steps?".
# Think of navd as "how do I hold on to a set of favorite directories, and easily switch between them?".
# Pseudo-code to explain each part of the "navd" bash function just below:
#              If no arguments to the 'navd' command:
#                  If stack has entries, then print the stack one-line-per-dir with each line numbered.
#                  Else, if stack is empty, automatically run the equivalent of the navh command.
#              Else (there **are** arguments to the 'navd' command):
#                  If arg is '--help' or '/?' then show help.
#                  Else    (arg is assumed to be a path to a directory)
#                      Remember the directory we are starting at
#                      Change to dir given as argument (the "arg-dir"), and do a few chores:
#                      Do not use arg-dir literally ... instead, magically put the **absolute** path we arrived at into history.
#                      Set a flag if the arg-dir is already in the stack.
#                      If the flag is set then just show the stack (on one line), else ADD to stack, ROTATE to end-of-stack, and show the stack.
#                      Change to dir we started at and then back to the arg-dir. This allows "cd -" to go back to dir we started at.
#                  End-If
#              End-If
navd () {
    if [[ $1 == '' ]]; then                             #--no arguments to the 'navd' command
        if dirs +1 >/dev/null 2>&1; then                #------stack has entries
            dirs -p | Perl -ne 'print (-1+$cn++); print "$_"' | grep -v "^-1";
        else                                            #------stack is empty
            echo "The navd stack is empty. Now running 'navh' in case that's helpful. navd --help works."
            if [[ ! -f $HOME/.navhignore ]]; then echo -n ''>>$HOME/.navhignore;fi;diff --new-line-format="" --unchanged-line-format="" <(history | Perl -ne "if (m/^\s*\d+\s+navd [\"~.\/]/) {s/^\s*\d+\s+/  /;s/\/$//;print}" | sort -u) <(cat $HOME/.navhignore | sort -u);echo "cat $HOME/.navhignore # (Has "`grep -c . <(sort -u $HOME/.navhignore)`" unique lines.)"
        fi
    else                                                #--(there **are** arguments to the 'navd' command)
        if [[ $1 == '--help' || $1 == '/?' ]]; then     #------arg is '--help' or '/?'
            echo "The 'navd' functionality is nothing but one bash function and a set of aliases."
            echo "It offers a different style of handy directory navigation than pushd/popd."
            echo "It uses the same 'stack' as pushd. Look in the .bashrc file for details."
            echo "    (Think of pushd/dirs/popd as 'how do I retrace my steps?'."
            echo "     Think of navd as 'how do I remember a set of favorite directories,"
            echo "     and easily switch between them?'.)"
            echo "As of 10/2015, this link has more info: http://unix.stackexchange.com/a/229161"
            echo "Here is the set of navd-related aliases. None need any parameter:"
            alias | grep 'alias nav' | cut -d= -f1 | grep -v '-' | grep -v 'navh'
            alias | grep 'alias nav' | cut -d= -f1 | grep '-'
            echo "alias navh  # The 'navh' alias has nothing to display until a 'navd <path>' is run. Short for nav-history."
            echo "---- To get started, simpy type navd followed by your favorite path. ----"
            echo "---- navd with no param shows stack. nav0 navigates to first on stack. ----"
        else                                            #------(arg is assumed to be a path to a directory)
            mypwd="$PWD"
            cd "$1" >/dev/null;
            history -s `echo "$PWD" | Perl -pe 's/$ENV{'HOME'}/~/;s/ /\\\\ /g;s/^/navd /'`
            myflag=`dirs -p | Perl -pe 's/\n/:/' | Perl -ne '@a=split(":");$pwd=shift(@a);$flag=0;foreach (@a) {if ($_ eq $pwd) {$flag=1}};print $flag'`
            if [[ $myflag == 1 ]]; then dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"; else pushd .>/dev/null; pushd +1>/dev/null; dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"; fi
            cd "$mypwd"; cd "`dirs -l -0`"
        fi
    fi
};
# Aliases for navigating and rotating the "pushd" stack in the style of "navd":
alias navd0='cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"' # "-l" is dash-L, and expands "~" to denote the home dir. Needed inside back-ticks.
alias navd1='cd "`dirs -l +1`";pushd -n +1;cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd2='myd=$PWD;cd "`dirs -l +1`";for i in {1..2};do pushd -n +1>/dev/null;cd "`dirs -l +1`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd3='myd=$PWD;cd "`dirs -l +1`";for i in {1..3};do pushd -n +1>/dev/null;cd "`dirs -l +1`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd4='myd=$PWD;cd "`dirs -l +1`";for i in {1..4};do pushd -n +1>/dev/null;cd "`dirs -l +1`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd5='myd=$PWD;cd "`dirs -l +1`";for i in {1..5};do pushd -n +1>/dev/null;cd "`dirs -l +1`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd6='myd=$PWD;cd "`dirs -l +1`";for i in {1..6};do pushd -n +1>/dev/null;cd "`dirs -l +1`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd7='myd=$PWD;cd "`dirs -l +1`";for i in {1..7};do pushd -n +1>/dev/null;cd "`dirs -l +1`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd8='myd=$PWD;cd "`dirs -l +1`";for i in {1..8};do pushd -n +1>/dev/null;cd "`dirs -l +1`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd9='myd=$PWD;cd "`dirs -l +1`";for i in {1..9};do pushd -n +1>/dev/null;cd "`dirs -l +1`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-1='cd "`dirs -l -0`";pushd -n -0>/dev/null; dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-2='myd=$PWD;cd "`dirs -l -0`";pushd -n -0>/dev/null;cd "`dirs -l -0`";pushd -n -0>/dev/null;cd "$myd";cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-3='myd=$PWD;cd "`dirs -l -0`";for i in {1..3};do pushd -n -0>/dev/null;cd "`dirs -l -0`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-4='myd=$PWD;cd "`dirs -l -0`";for i in {1..4};do pushd -n -0>/dev/null;cd "`dirs -l -0`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-5='myd=$PWD;cd "`dirs -l -0`";for i in {1..5};do pushd -n -0>/dev/null;cd "`dirs -l -0`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-6='myd=$PWD;cd "`dirs -l -0`";for i in {1..6};do pushd -n -0>/dev/null;cd "`dirs -l -0`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-7='myd=$PWD;cd "`dirs -l -0`";for i in {1..7};do pushd -n -0>/dev/null;cd "`dirs -l -0`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-8='myd=$PWD;cd "`dirs -l -0`";for i in {1..8};do pushd -n -0>/dev/null;cd "`dirs -l -0`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-9='myd=$PWD;cd "`dirs -l -0`";for i in {1..9};do pushd -n -0>/dev/null;cd "`dirs -l -0`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
# BONUS commands (beyond the 20). Aliases for navigating but NOT rotating the "navd" stack:
#      Help in remembering: "navd<#>" does more since it both changes the PWD and rotates the stack, whereas "nav<#>" does less
#            (and has one letter less) since "nav<#>" only changes the PWD. Also "navd<#>" acts like the pushd-related command: dirs
#      There is no "nav" command (with no number) so that there will be no conflict if any program called "nav" is used.
alias nav0='cd "`dirs -l +1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav1='cd "`dirs -l +2`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav2='cd "`dirs -l +3`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav3='cd "`dirs -l +4`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav4='cd "`dirs -l +5`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav5='cd "`dirs -l +6`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav6='cd "`dirs -l +7`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav7='cd "`dirs -l +8`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav8='cd "`dirs -l +9`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav9='cd "`dirs -l +10`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-1='cd "`dirs -l -0`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-2='cd "`dirs -l -1`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-3='cd "`dirs -l -2`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-4='cd "`dirs -l -3`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-5='cd "`dirs -l -4`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-6='cd "`dirs -l -5`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-7='cd "`dirs -l -6`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-8='cd "`dirs -l -7`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-9='cd "`dirs -l -8`";dirs -p | Perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
# BONUS command (beyond the 20). Alias for showing 'history' of all navd commands that add to the stack.
#                Can be used in a new terminal session to quickly add recently used dirs to the navd stack.
alias navh='if [[ ! -f $HOME/.navhignore ]]; then echo -n ''>>$HOME/.navhignore;fi;diff --new-line-format="" --unchanged-line-format="" <(history | Perl -ne "if (m/^\s*\d+\s+navd [\"~.\/]/) {s/^\s*\d+\s+/  /;s/\/$//;print}" | sort -u) <(cat $HOME/.navhignore | sort -u);echo "cat $HOME/.navhignore # (Has "`grep -c . <(sort -u $HOME/.navhignore)`" unique lines.)"'
# Note: When 'navd <relative-path>' is used, then by bash-magic the navd command puts 'navd <absolute-path>' into history,
#       instead. This allows the output of "navh" to be useful regardless of the directory that is current when it is run.
#
# BONUS commands (beyond the 20). An even shorter alias for navd. An even shorter alias for navh.
alias nd='navd'
alias nh='if [[ ! -f $HOME/.navhignore ]]; then echo -n "">>$HOME/.navhignore;fi;diff --new-line-format="" --unchanged-line-format="" <(history | Perl -ne "if (m/^\s*\d+\s+navd [\"~.\/]/) {s/^\s*\d+\s+/  /;s/\/$//;print}" | sort -u) <(cat $HOME/.navhignore | sort -u);echo "cat $HOME/.navhignore # (Has "`grep -c . <(sort -u $HOME/.navhignore)`" unique lines.)"'

Esses aliases são baseados em comandos "bash". Cuidado especial é tomado para preservar o comportamento normal de "cd -". (Muitas vezes eu uso "cd -" em vez de me preocupar com pushd ou navd - porque "cd -" é muito útil para voltar ao último "lugar" em que você estava, ou alternar entre apenas 2 lugares, e funciona em qualquer lugar sem instalação.)

Esses comandos podem, é claro, ser colocados no arquivo .bashrc para uma instalação mais permanente deles.

1
Dana Forsberg

Aqui está outra solução de que você pode gostar. Escrevi isso depois de brincar com a solução de @cjm. Ele usa o comando de diálogo para criar um menu do tipo ncurses a partir da saída de dirs. Selecionar um item trará esse diretório para o topo da pilha e fará o cd nele. Isso tem a vantagem sobre o dirhistory de dar a cada emulador de terminal seu próprio buffer de histórico de diretório e ser um pouco mais fácil de instalar.

Para instalar: Depois de criar o alias de cd para pushd, instale a caixa de diálogo e coloque esta função em seu bashrc:

dirmenu(){
    dirIter=$(dialog --backtitle 'dirmenu' --clear --cancel-label "Exit" --menu "Please select:" 0 0 0 $(dirs) 3>&2 2>&1 1>&3)
    cmd="builtin cd ~$dirIter"
    eval $cmd
}

Eu gosto disso um pouco mais do que executar dirs -v e, em seguida, executar outro comando para abrir ou cd para o diretório que desejo. Os menus de diálogo também podem ser altamente personalizados por meio de seu dialogrc.

Então, para responder à sua pergunta, sim, acho que aliasing pushd para cd é uma ótima idéia. É improvável que você tenha problemas de estouro de buffer se estiver reiniciando sua máquina regularmente, pelo menos para atualizações. Embora eu tenha cuidado ao usar cd ao fazer scripts; cd em um loop while pode causar problemas de estouro de buffer. Não tenho certeza do que controla o tamanho do buffer dirs/pushd.

0
Overdr0ne