Esiste un one-liner che mi consente di creare una directory e spostarci in essa contemporaneamente?


150

Mi ritrovo a ripetere molto:

mkdir longtitleproject
cd longtitleproject

C'è un modo per farlo in una riga senza ripetere il nome della directory? Sono a bash qui.



2
Correlato (ma più generale): esegui due comandi su un argomento (senza script) .
G-Man,

1
mkdir longtitleprojectquindicd !^
user262826

Risposte:


160

Non esiste un comando integrato, ma puoi facilmente scrivere una funzione che chiama mkdirquindi cd:

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

Inserisci questo codice nel tuo ~/.bashrcfile (o ~/.kshrcper utenti ksh o ~/.zshrcper utenti zsh). Definisce una funzione chiamata mkcd. "$1"verrà sostituito dall'argomento della funzione quando lo si esegue.

Questa versione semplice presenta diversi difetti:

  • Non è possibile creare una catena di sottodirectory contemporaneamente. Correzione: passare l' -popzione a mkdir. (Ciò può essere o non essere desiderabile, poiché aumenta il rischio che un errore di battitura non venga rilevato, ad esempio, mkcd mydierctory/newsubsi creerà felicemente mydierctorye mydierctory/newsubquando si intende creare newsuball'interno dell'esistente mydirectory.)
  • Se l'argomento inizia con -ma non è giusto -, allora mkdire cdlo interpreterà come un'opzione. Se è giusto -, allora cdlo interpreterà nel senso $OLDPWD. Se è +seguito da 0 o più cifre, cdin zsh lo interpreterà come un indice nello stack della directory. Puoi risolvere il primo problema, ma non gli altri due, passando --prima dell'argomento. Puoi risolvere tutti questi problemi anteponendo ./all'argomento se si tratta di un percorso relativo.
  • mkdirnon segue CDPATH, ma lo cdfa, quindi se hai impostato CDPATHun valore che non inizia con .(una configurazione certamente un po 'insolita), allora cdpotresti portarti in una directory diversa da quella appena creata. La preparazione ./ai percorsi relativi risolve questo problema (causa CDPATHdi essere ignorato).
  • Se mkdirfallisce, prova a eseguire cd. Correzione: utilizzare &&per separare i due comandi.

Ancora abbastanza semplice:

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

Questa versione ha ancora il potenziale per far cdpassare una directory diversa da quella mkdirappena creata in un caso limite: se l'argomento mkcdcontiene ..e passa attraverso un collegamento simbolico. Ad esempio, se la directory corrente è /tmp/hereed mylinkè un collegamento simbolico a /somewhere/else, quindi mkdir mylink/../foocrea /somewhere/else/foomentre cd mylink/../foocambia in foo. Non è sufficiente cercare i collegamenti simbolici nell'argomento, perché la shell tiene traccia anche dei collegamenti simbolici nella propria directory corrente, quindi cd /tmp/mylink; mkdir ../foo; cd ../foonon cambia nella nuova directory ( /somewhere/else/foo) ma in /tmp/foo. Una soluzione per questo è lasciare che il cdbuiltin risolva prima tutti i ..componenti del percorso (non ha senso usare foo/..iffoonon esiste, quindi mkdirnon è mai necessario vederne nessuno ..).

Veniamo a questa versione robusta anche se leggermente cruenta:

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
}

(Esercizio: perché sto usando una subshell per la prima cdchiamata?)

Se mkdir fallisce, voglio essere sicuro di non cambiare la directory corrente. Tornare indietro con cd - o $ OLDPWD non è abbastanza buono se la shell non ha i permessi per cambiare nella sua directory corrente. Inoltre, chiamando gli aggiornamenti cd OLDPWD, quindi vogliamo farlo una sola volta (o ripristinare OLDPWD).


Esistono anche modi meno specializzati per non dover riscrivere la parola dalla riga precedente:

  • Digitare cd , quindi Esc .(o Alt+ .) per inserire l'ultimo argomento dal comando precedente.
  • cd !$esegue cdl'ultimo argomento del comando precedente.
  • Premere Upper richiamare la riga di comando precedente, quindi modificarla per cambiarla mkdirin cd.

Grazie! l'Esc. mi sembra il più conveniente, la sequenza di tasti ha un significato speciale?
methodofaction

È solo la sequenza di Bash (ed ereditata da ksh, e funziona anche zsh) per "ripetere l'ultima parola del comando precedente". Lo uso abbastanza spesso.
Geekosaur,

31
@Gilles Sto iniziando a pensare che l'account "Gilles" sia effettivamente condiviso da un gruppo di esperti. ;-)
Keith

@StephaneChazelas /a/b/..//funzionerebbe davvero ma non /a/b/../c. Fisso. Ho posto la domanda a un pubblico più vasto.
Gilles,

1
mkcd() { mkdir -p "$1" && cd "$1"; }non sembra essere un problema in (la mia istanza di) 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(include l'installazione e) visualizza /tmp/here/fooqual è ciò che è stato creato (e ciò che mi aspettavo). bashcrea e cambia erroneamente in /var/tmp/somewhere/foo.
Adam Katz,

134

Questa è la linea di cui hai bisogno. Non sono necessarie altre configurazioni:

mkdir longtitleproject && cd $_

La $_variabile, in bash, è l'ultimo argomento dato al comando precedente. In questo caso, il nome della directory appena creata. Come spiegato in 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.

Utilizzare cd $_per recuperare l'ultimo argomento del comando precedente anziché cd !$perché cd !$fornisce l'ultimo argomento del comando precedente nella cronologia della shell :

cd ~/
mkdir folder && cd !$

finisci a casa (o ~ /)

cd ~/
mkdir newfolder && cd $_

finisci in newfolder sotto casa !! (o ~ / newfolder)


23
Perché sulla Terra questa non è la risposta accettata
JSmyth,

1
@JSmyth Sono d'accordo, questo è un one-liner che utilizza la funzionalità shell nativa
sming

Penso che l'OP stia cercando di evitare di usare i due comandi. Questa risposta è (quasi) valida quanto fare mkdir foo && cd foo, il che non è utile.
josemigallas,

7
L'OP sta chiedendo un one-liner che non richiede di ripetere il nome della directory, e questo è tutto
Jesús Carrera

Questo è il tradizionale one-liner a cui ti riferisci o che hai visto usare in altri documenti / tutorial. In realtà ci sono 3 risposte perfette qui. Questo, quello di @ jordan-harris, e la risposta selezionata. Dipende dalla configurazione e dalle preferenze.
Guadagna il

30

Non mi sarebbe mai venuto in mente di scrivere questo comportamento perché inserisco quanto segue su base oraria ...

$ mkdir someDirectory<ENTER>
$ cd !$

dove bash sostituisce gentilmente !$con l'ultima parola dell'ultima riga; cioè il nome della directory lunga che hai inserito.

Inoltre, il completamento del nome file è tuo amico in tali situazioni. Se la tua nuova directory fosse l'unico file nella cartella, un doppio veloce TABti darebbe la nuova directory senza reinserirla.

Sebbene sia bello che bash ti permetta di scrivere script su attività comuni come suggeriscono le altre risposte, penso che sia meglio imparare le funzionalità di modifica della riga di comando che bash ha da offrire in modo che quando lavori su un altro computer non ti manca la sintattica zucchero fornito dagli script personalizzati.


1
C'è un buon posto per scoprire le stranezze bash più importanti come questa?
Dominicbri7,

@ dominicbri7 Generalmente si trova in "modifica della riga di comando bash". Lo stesso utilizzo di Google fornisce quanto segue come risultato principale web.mit.edu/gnu/doc/html/features_7.html Più specificamente ,! $ è un esempio di un Word Designator, vedi gnu. org / software / bash / manual / bashref.html # Word-Designators
Rob

17

Secondo Quali personalizzazioni hai fatto sul tuo profilo shell per aumentare la produttività? , ecco come lo faccio:

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

significa che funziona anche se la directory esiste già.


4
L' -popzione per mkdir eliminerà gli errori.
Glenn Jackman,

1
mcd è un comando già esistente. Anche se hai appena fatto un esempio, l'ho usato da solo in quanto è una lettera più corta di mkcd.
Dharmit,

@Dharmit Shah: qual è il mcdcomando esistente ? Quale pacchetto o progetto fornisce questo comando?
Mikel,

2
mtools fornisce il comando mcd. La sua pagina man dice "Il comando mcd è usato per cambiare la directory di lavoro di mtools sul disco MS-DOS."
Dharmit,

13

Se usi Oh My Zsh, c'è un comando chiamato take che fa esattamente questo. Sembrerebbe qualcosa del genere.

take myfolder

In realtà l'ho trovato per caso. Ho appena guardato ed è elencato su questo cheatheat dal wiki Oh My Zsh GitHub. È un comando abbastanza utile e apparentemente molto facile da creare.


1
Non ne ho mai saputo take:) Perfetto! btw - iTerm2 con Oh My Zsh. In realtà ci sono 3 risposte perfette qui. Questo, quello di @ jesús-carrera, e la risposta selezionata. Dipende dalla configurazione e dalle preferenze.
Guadagna il

3

Oppure potresti semplicemente creare una breve variabile al volo e usarla due volte x = longproject ; mkdir $x ; cd $x- che ammetto sia ancora più lunga rispetto all'utilizzo di una funzione shellscript :)


0

Ecco una leggera variante che è degna di menzione:

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

Aggiungi questo al tuo ~/.bash_profilee puoi quindi usarlo mkdirnormalmente (una volta che lo hai sourcefatto), tranne ora che eseguirà la funzione sopra anziché il mkdircomando standard .

Nota, questo non convalida l'input secondo la risposta accettata da Gilles , ma dimostra come puoi (efficacemente) ignorare i builtin.

Dai documenti (parafrasando leggermente):

command mkdir [args]corre mkdircon argsignorando qualsiasi funzione di shell di nome mkdir. Vengono eseguiti solo i comandi incorporati della shell o i comandi trovati cercando nel PERCORSO. Se esiste una funzione shell denominata ls, l'esecuzione command lsall'interno della funzione eseguirà il comando esterno lsinvece di chiamare la funzione in modo ricorsivo

Credo che builtinraggiunga un risultato simile a command.


dovresti assolutamente citare$dir
Jeff Schaller

@Jeff, d'accordo, ma la risposta accettata ha tutta la convalida di cui avremmo bisogno. Sto solo presentando l'uso di commandcome alternativa.
Arj,

0

Aggiunta della funzione di supporto a BASH, ZSH o KSH

Crea un mkcdcomando per il tuo ambiente in una riga

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


-1

Ho appena automatizzato le risposte di cui sopra e creato uno script eseguibile una sola volta:

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

echo "$fun" >> ~/.bashrc

Basta copiarlo in un nuovo file mkcd.shed eseguirlo solo una volta nel terminale da bash mkcd.sh. Quindi esegui source ~/.bashrcper farlo funzionare nella sessione corrente.

Successivamente, è possibile utilizzare mkcd some_dirper creare e immettere direttamente in quella directory.


Suggerisci di scrivere uno script (in un file) il cui unico scopo è quello di aggiungere al ~/.bashrcfile (con una risposta che è già stata data)? E come suggerisci di creare questo mkcd.shscript? Con un editore, forse? Sembra più lavoro che semplice modifica ~/.bashrc. Che vantaggio ha questo rispetto alla risposta accettata? ... ... ... ... ... ... ... .... ... ... ...
Scott,

Mi dispiace dirlo, ma sì, come ho scritto nella mia risposta, ho usato le risposte di cui sopra. Funziona Se non mi credi, provalo. E per non provare, oggi ho usato il mio giorno intero per scrivere tali script in bash e python.
subtleseeker,

Ho provato quello che hai scritto. Esso non funziona.
Scott,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.