Existe um one-liner que me permite criar um diretório e movê-lo ao mesmo tempo?

125

Eu me vejo repetindo muito:

mkdir longtitleproject
cd longtitleproject

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

    
por Duopixel 12.03.2011 / 02:15

10 respostas

139

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

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

Coloque este código no seu arquivo ~/.bashrc (ou ~/.kshrc para usuários do ksh ou ~/.zshrc para usuários do zsh). Define uma função chamada mkcd . "$1" será substituído pelo argumento da função quando você executá-lo.

Esta versão simples tem vários defeitos:

  • Você não pode criar uma cadeia de subdiretórios de uma só vez. Correção: passe a opção -p 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/newsub terá prazer em criar mydierctory e mydierctory/newsub quando você pretende criar newsub dentro do mydirectory existente.)
  • Se o argumento começar com - , mas não for apenas - , então mkdir e cd o interpretarão como uma opção. Se for apenas - , então cd interpretará como $OLDPWD . Se for + seguido por 0 ou mais dígitos, então cd em zsh irá interpretá-lo 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, adicionando ./ ao argumento se for um caminho relativo.
  • mkdir não segue CDPATH , mas cd , portanto, se você definiu CDPATH como um valor que não começa com . (uma configuração reconhecidamente um tanto incomum), então cd pode levar você a um diretório diferente daquele que acabou de ser criado. Colocar ./ nos caminhos relativos corrige isso (faz com que CDPATH seja ignorado).
  • Se mkdir falhar, ele tentará 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"
}

Esta versão ainda tem o potencial de tornar cd em um diretório diferente daquele que mkdir acabou de criar em um caso de borda: se o argumento para mkcd contiver .. e passar por um link simbólico . Por exemplo, se o diretório atual for /tmp/here e mylink for um link simbólico para /somewhere/else , então mkdir mylink/../foo criará /somewhere/else/foo , enquanto cd mylink/../foo será alterado 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 é alterado para o novo diretório ( /somewhere/else/foo ), mas para /tmp/foo . Uma correção para isso é deixar o cd builtin resolver todos os componentes .. path primeiro (não faz sentido usar foo/.. if foo não existe, portanto mkdir nunca precisa ver nenhum .. ).

Chegamos a essa 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 para a primeira chamada cd ?)

If mkdir fails, I want to be sure not to change the current directory. Changing back with cd - or $OLDPWD isn't good enough if the shell doesn't have permission to change into its current directory. Also, calling cd updates OLDPWD, so we only want to do it once (or restore OLDPWD).

Há também formas menos especializadas de não precisar redigitar a palavra da linha anterior:

  • Digite cd , então Esc . (ou Alt + . ) para inserir o último argumento do comando anterior.
  • cd !$ executa cd no último argumento do comando anterior.
  • Pressione Para cima para recuperar a linha de comando anterior e edite-a para alterar mkdir para cd .
por 12.03.2011 / 02:26
112

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

mkdir longtitleproject && cd $_

A variável $_ , no bash, é o último argumento dado ao comando anterior. Nesse caso, o nome do diretório que você acabou de criar. Conforme 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 newfolder em casa !! (ou ~ / newfolder)

    
por 01.08.2015 / 13:21
28

Nunca me ocorreu escrever este comportamento porque eu insiro o seguinte numa base quase horária ...

$ mkdir someDirectory<ENTER>
$ cd !$

em que bash gentilmente substitui !$ pela ú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 em tais situações. Se o seu novo diretório era o único arquivo na pasta, uma rápida dupla TAB lhe daria o novo diretório sem reinseri-lo.

Embora seja legal que o bash permita que você crie scripts para tarefas comuns como as outras respostas sugerem, é 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 perdendo o açúcar sintático que seus scripts personalizados fornecem.

    
por 15.03.2011 / 20:56
16

De acordo com What personalizações que 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.

    
por 12.03.2011 / 04:21
8

Se você usa Oh My Zsh, existe um comando chamado take que faz exatamente isso. Seria algo como isto.

take myfolder

Eu realmente encontrei este por acaso. Acabei de ver e está listado em este cheatsheat do Oh My Wiki do Zsh GitHub. É um comando bastante útil e aparentemente muito fácil de se criar.

    
por 20.08.2015 / 09:31
3

Ou você poderia 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 longo do que usar uma função shellscript:)

    
por 12.03.2011 / 11:33
0

Eu fiz um script que cria o diretório e, em seguida, cd's para ele, então eu dei-lhe um alias. E aqui está uma essência onde eu descrevo.

link

    
por 23.12.2015 / 13:29
0

Aqui está uma pequena variante que é digna de menção:

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

Adicione isto ao seu ~/.bash_profile e você pode usar mkdir como normal (uma vez que você tenha source d), exceto que agora ele irá executar a função acima ao invés do comando padrão mkdir .

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

A partir dos documentos (parafraseando um pouco):

command mkdir [args] runs mkdir with args ignoring any shell function named mkdir. Only shell builtin commands or commands found by searching the PATH are executed. If there is a shell function named ls, running command ls within the function will execute the external command ls instead of calling the function recursively

Acredito que builtin atinge um resultado semelhante a command .

    
por 06.09.2017 / 19:18
0

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

Crie o comando mkcd para o seu ambiente em uma linha

echo -e 'mkcd() {\n mkdir -p "$1" && cd $_\n}' >> ~/.${0//-/}rc && . ~/.${0//-/}rc
    
por 14.07.2018 / 17:22
-1

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

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

echo "$fun" >> ~/.bashrc

Copie isso em um novo arquivo mkcd.sh e execute-o somente uma vez no terminal em bash mkcd.sh . Em seguida, execute source ~/.bashrc para fazê-lo funcionar na sessão atual.

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

    
por 11.12.2017 / 21:24