Existe uma linha que me permita criar um diretório e movê-lo ao mesmo tempo?

150

Encontro-me repetindo muito:

mkdir longtitleproject
cd longtitleproject

Existe uma maneira de fazer isso em uma linha sem repetir o nome do diretório? Estou na festa aqui.

methodofaction
fonte
2
Relacionado (mas mais geral): Execute dois comandos em um argumento (sem script) .
G-Man
1
mkdir longtitleprojectentãocd !^
user262826
Também foi abordado em askubuntu.com/q/927463/295286 e askubuntu.com/q/249314/295286
Sergiy Kolodyazhnyy

Respostas:

160

Não há comando interno, mas você pode escrever facilmente uma função que chama mkdirentão cd:

mkcd () {
  mkdir "$1"
  cd "$1"
}

Coloque esse código no seu ~/.bashrcarquivo (ou ~/.kshrcpara usuários ksh ou ~/.zshrcpara usuários zsh). Ele define uma função chamada mkcd. "$1"será substituído pelo argumento da função quando você a executar.

Esta versão simples possui vários defeitos:

  • Você não pode criar uma cadeia de subdiretórios de uma vez. Correção: passe a -popção para mkdir. (Isso pode ou não ser desejável, pois aumenta o risco de um erro de digitação não ser detectado, por exemplo, mkcd mydierctory/newsubcriará com alegria mydierctorye mydierctory/newsubquando você pretende criar newsubdentro do existente mydirectory.)
  • Se o argumento começa com -, mas não é apenas -, em seguida, mkdire cdirá interpretá-lo como uma opção. Se for justo -, então cdo interpretará como significando $OLDPWD. Se for +seguido por 0 ou mais dígitos, o cdzsh o interpretará como um índice na pilha de diretórios. Você pode corrigir o primeiro problema, mas não os outros dois, passando --antes do argumento. Você pode corrigir todos esses problemas anexando ./o argumento se for um caminho relativo.
  • mkdirnão segue CDPATH, mas segue ; cdportanto, se você definiu CDPATHum valor que não começa com .(uma configuração reconhecidamente um tanto incomum), cdpoderá levá-lo para um diretório diferente daquele que foi criado. A adição ./de caminhos relativos corrige isso (faz CDPATHcom que seja ignorado).
  • Se mkdirfalhar, ele tenta executar cd. Correção: use &&para separar os dois comandos.

Ainda bastante simples:

mkcd () {
  case "$1" in /*) :;; *) set -- "./$1";; esac
  mkdir -p "$1" && cd "$1"
}

Essa versão ainda tem o potencial de cdentrar em um diretório diferente daquele que mkdiracabou de ser criado em um caso de borda: se o argumento mkcdcontiver ..e passar por um link simbólico. Por exemplo, se o diretório atual é /tmp/heree mylinké um link simbólico para /somewhere/else, em seguida, mkdir mylink/../foocria /somewhere/else/fooenquanto cd mylink/../foomuda para foo. Não é suficiente procurar links simbólicos no argumento, porque o shell também rastreia links simbólicos em seu próprio diretório atual, portanto cd /tmp/mylink; mkdir ../foo; cd ../foo, não muda para o novo diretório ( /somewhere/else/foo), mas para /tmp/foo. Uma correção para isso é permitir que o cdinterno resolva todos os ..componentes do caminho primeiro (não faz sentido usar foo/..sefoonão existe, então mkdirnunca precisa ver nenhum ..).

Chegamos a esta versão robusta, embora um pouco sangrenta:

mkcd () {
  case "$1" in
    */..|*/../) cd -- "$1";; # that doesn't make any sense unless the directory already exists
    /*/../*) (cd "${1%/../*}/.." && mkdir -p "./${1##*/../}") && cd -- "$1";;
    /*) mkdir -p "$1" && cd "$1";;
    */../*) (cd "./${1%/../*}/.." && mkdir -p "./${1##*/../}") && cd "./$1";;
    ../*) (cd .. && mkdir -p "${1#.}") && cd "$1";;
    *) mkdir -p "./$1" && cd "./$1";;
  esac
}

(Exercício: por que estou usando um subshell na primeira cdchamada?)

Se o mkdir falhar, quero ter certeza de não alterar o diretório atual. Mudar de volta com cd - ou $ OLDPWD não é bom o suficiente se o shell não tiver permissão para mudar para o diretório atual. Além disso, a chamada de CD atualiza o OLDPWD, portanto, queremos fazê-lo apenas uma vez (ou restaurar o OLDPWD).


Também existem maneiras menos especializadas de não precisar digitar novamente a palavra da linha anterior:

  • Digite cd , então Esc .(ou Alt+ .) para inserir o último argumento do comando anterior.
  • cd !$executa cdno último argumento do comando anterior.
  • Imprensa Upde recordar a linha de comando anterior, em seguida, editá-lo para mudar mkdirpara cd.
Gilles
fonte
Obrigado! o Esc. me parece mais conveniente, a sequência de teclas tem algum significado especial?
methodofaction
É apenas a sequência Bash (e herdada de ksh, e também funciona em zsh) para "repetir a última palavra do comando anterior". Eu o uso com bastante frequência.
Geekosaur #
31
@Gilles Começo a pensar que a conta "Gilles" é realmente compartilhada por um painel de especialistas. ;-)
Keith
@StephaneChazelas /a/b/..//realmente funcionaria, mas não /a/b/../c. Fixo. Eu coloquei a questão para um público mais amplo.
Gilles
1
mkcd() { mkdir -p "$1" && cd "$1"; }não parece ser um problema no (meu exemplo de) zsh. mkdir -p /var/tmp/somewhere/else /tmp/here; cd /tmp/here; ln -s /var/tmp/somewhere/else mylink; mkdir -p mylink/../foo && cd mylink/../foo; pwd(inclui a configuração e) exibe o /tmp/here/fooque foi criado (e o que eu esperava). bashcria e altera erroneamente para /var/tmp/somewhere/foo.
Adam Katz
134

Este é o one-liner que você precisa. Nenhuma outra configuração é necessária:

mkdir longtitleproject && cd $_

A $_variável, em bash, é o último argumento dado ao comando anterior. Nesse caso, o nome do diretório que você acabou de criar. Como explicado em man bash:

_         At  shell  startup,  set to the absolute pathname used to invoke
          the shell or shell script being executed as passed in the  envi
          ronment  or  argument  list.   Subsequently, expands to the last
          argument to the previous command, after expansion.  Also set  to
          the  full  pathname  used  to  invoke  each command executed and
          placed in the environment exported to that command.  When check
          ing  mail,  this  parameter holds the name of the mail file cur
          rently being checked."$_" is the last argument of the previous command.

Use cd $_para recuperar o último argumento do comando anterior em vez de cd !$porque cd !$fornece o último argumento do comando anterior no histórico do shell :

cd ~/
mkdir folder && cd !$

você acaba em casa (ou ~ /)

cd ~/
mkdir newfolder && cd $_

você acaba em uma nova pasta em casa !! (ou ~ / nova pasta)

Jesús Carrera
fonte
23
Por que na Terra esta não é a resposta aceita
JSmyth
1
@JSmyth Concordo, este é um one-liner que usa a funcionalidade shell nativa
sming
Eu acho que o OP está tentando evitar o uso dos dois comandos. Esta resposta é (quase) tão válida quanto fazer mkdir foo && cd foo, o que não é útil.
Jsemigallas
7
O OP está pedindo um one-liner que não necessita de repetir o nome do diretório, e é isso
Jesús Carrera
Este é o one-liner tradicional a que você está se referindo ou que já viu outros usarem em documentos / tutoriais. Na verdade, existem 3 respostas perfeitas aqui. Este, o de @ jordan-harris, e a resposta selecionada. Depende da sua configuração e preferência.
Wade
30

Nunca me ocorreu escrever esse comportamento porque eu insiro o seguinte quase que de hora em hora ...

$ mkdir someDirectory<ENTER>
$ cd !$

onde bash gentilmente substitui !$a última palavra da última linha; ou seja, o nome do diretório longo que você digitou.

Além disso, a conclusão do nome do arquivo é seu amigo nessas situações. Se o seu novo diretório fosse o único arquivo na pasta, um duplo rápido TABforneceria o novo diretório sem precisar digitá-lo novamente.

Embora seja legal que o bash permita que você crie scripts de tarefas comuns, como as outras respostas sugerem, acho melhor aprender os recursos de edição de linha de comando que o bash tem a oferecer para que, quando você estiver trabalhando em outra máquina, não perca a sintaxe sintática. açúcar que seus scripts personalizados fornecem.

Roubar
fonte
1
Existe um bom lugar para descobrir as peculiaridades mais importantes do bash como esta?
precisa saber é o seguinte
@ dominicbri7 Geralmente vem em "edição de linha de comando do bash". O mesmo recurso no Google dá o seguinte resultado: web.mit.edu/gnu/doc/html/features_7.html Mais especificamente,! $ é um exemplo de um Designador de Palavras, veja o gnu. org / software / bash / manual / bashref.html # Designadores de palavras
Rob
17

De acordo com Quais personalizações você fez no seu perfil de shell para aumentar a produtividade? , é assim que eu faço:

# make a directory and cd to it
mcd()
{
    test -d "$1" || mkdir "$1" && cd "$1"
}

significa que também funciona se o diretório já existir.

Mikel
fonte
4
A -popção para mkdir suprimirá erros.
glenn jackman
1
mcd é um comando já existente. Embora você tenha apenas dado um exemplo, eu o usei por ser uma letra menor que o mkcd.
Dharmit
@Dharmit Shah: Qual é o mcdcomando existente ? Qual pacote ou projeto fornece esse comando?
11117 Mikel
2
mtools fornece o comando mcd. Sua página do manual diz "O comando mcd é usado para alterar o diretório de trabalho do mtools no disco do MS-DOS".
Dharmit
13

Se você usar Oh My Zsh, há um comando chamado take que faz exatamente isso. Seria algo assim.

take myfolder

Na verdade, encontrei este por acidente. Eu apenas olhei e está listado neste truque do wiki Oh My Zsh GitHub. É um comando bastante útil e aparentemente muito fácil de se criar.

Jordan Harris
fonte
1
Eu nunca soube sobre take:) Perfeito! btw - iTerm2 com Oh My Zsh. Na verdade, existem 3 respostas perfeitas aqui. Este, o de @ jesús-carrera, e a resposta selecionada. Depende da sua configuração e preferência.
Wade
3

Ou você pode simplesmente criar uma variável curta on-the-fly e usá-la duas vezes x = longproject ; mkdir $x ; cd $x- o que eu admito que ainda é mais do que usar uma função shellscript :)

sakisk
fonte
0

Aqui está uma pequena variante que vale a pena mencionar:

function mkdir() {
    local dir=$1
    command mkdir "$dir"  &&  cd "$dir"
}

Adicione isso ao seu ~/.bash_profilee você poderá usá-lo mkdirnormalmente (assim que o desejar source), exceto que agora ele executará a função acima, em vez do mkdircomando padrão .

Observe que isso não valida a entrada de acordo com a resposta aceita por Gilles , mas demonstra como você pode (efetivamente) substituir os componentes internos.

Dos documentos (parafraseando um pouco):

command mkdir [args]corre mkdircom argsignorando qualquer função shell chamado mkdir. Apenas comandos internos do shell ou comandos encontrados pesquisando o PATH são executados. Se houver uma função shell nomeada ls, a execução command lsdentro da função executará o comando externo em lsvez de chamar a função recursivamente

Eu acredito que builtinalcança um resultado semelhante ao command.

Arj
fonte
você definitivamente deveria citar$dir
Jeff Schaller
@ Jeff, concordou, mas a resposta aceita tem toda a validação necessária. Estou apenas apresentando o uso de commandcomo alternativa.
Arj
0

Adicionando função auxiliar ao BASH, ZSH ou KSH

Crie mkcdcomando para o seu ambiente em uma linha

echo -e 'mkcd() {\n mkdir -p "$1" && cd $_\n}' >> ~/.${0//-/}rc && . ~/.${0//-/}rc
Proximo
fonte
-1

Apenas automatizou as respostas acima e criou um script executável único:

fun='
mkcd ()
{
    mkdir -p -- "$1" && cd -P -- "$1"
}'

echo "$fun" >> ~/.bashrc

Apenas copie isso em um novo arquivo mkcd.she execute-o apenas uma vez no terminal por bash mkcd.sh. Em seguida, execute source ~/.bashrcpara fazê-lo funcionar na sessão atual.

Depois disso, você pode usar mkcd some_dirpara criar e inserir diretamente nesse diretório.

investigador
fonte
Você sugere escrever um script (em um arquivo) cujo único objetivo seja anexar ao ~/.bashrcarquivo (com uma resposta que já foi dada)? E como você sugere a criação desse mkcd.shscript? Com um editor, talvez? Parece mais trabalho do que apenas editar ~/.bashrc. Que vantagem isso tem sobre a resposta aceita? ....
Scott
Lamento dizer, mas sim, como escrevi na minha resposta, usei as respostas acima. Isso funciona. Se você não acredita em mim, tente. E sobre não tentar, usei meu dia inteiro para escrever esses scripts no bash e python hoje.
subtleseeker
Eu tentei o que você escreveu. Isso não funciona.
Scott