it-swarm.it

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

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.

166
methodofaction

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

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

Inserisci questo codice nel tuo ~/.bashrc file (o ~/.kshrc per utenti ksh o ~/.zshrc per utenti zsh). Definisce una funzione chiamata mkcd. "$1" verrà sostituito dall'argomento della funzione quando lo esegui.

Questa versione semplice presenta diversi difetti:

  • Non è possibile creare una catena di sottodirectory contemporaneamente. Correzione: passa il -p opzione su mkdir. (Ciò può essere o non essere desiderabile, poiché aumenta il rischio che un errore di battitura non venga rilevato, ad esempio mkcd mydierctory/newsub creerà felicemente mydierctory e mydierctory/newsub quando intendevi creare newsub all'interno dell'attuale mydirectory.)
  • Se l'argomento inizia con - ma non è solo -, quindi mkdir e cd lo interpreteranno come un'opzione. Se è solo -, quindi cd lo interpreterà nel senso di $OLDPWD. Se è + seguito da 0 o più cifre, quindi cd in 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.
  • mkdir non segue CDPATH, ma cd lo fa, quindi se hai impostato CDPATH su un valore che non inizia con . (una configurazione piuttosto insolita), quindi cd può portarti in una directory diversa da quella appena creata. Prepending ./ ai percorsi relativi risolve questo problema (fa sì che CDPATH venga ignorato).
  • Se mkdir non riesce, 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 sì che cd vada in una directory diversa da quella che mkdir ha appena creato in un caso Edge: se l'argomento di mkcd contiene .. e passa attraverso un collegamento simbolico. Ad esempio, se la directory corrente è /tmp/here e mylink è un collegamento simbolico a /somewhere/else, poi mkdir mylink/../foo crea /somewhere/else/foo mentre cd mylink/../foo diventa foo. Non è sufficiente cercare collegamenti simbolici nell'argomento, poiché Shell tiene traccia anche dei collegamenti simbolici nella propria directory corrente, quindi cd /tmp/mylink; mkdir ../foo; cd ../foo non cambia nella nuova directory (/somewhere/else/foo) ma in /tmp/foo. Una soluzione per questo è lasciare che cd builtin risolva tutto .. prima i componenti del percorso (non ha senso usare foo/.. se foo non esiste, quindi mkdir non deve mai vedere alcun ..).

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 chiamata cd?)

Se mkdir fallisce, voglio essere sicuro di non cambiare la directory corrente. Tornare indietro con cd - o $ OLDPWD non è abbastanza buono se 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 Word dalla riga precedente:

  • Digitare cd, quindi Esc. (o Alt+.) per inserire l'ultimo argomento dal comando precedente.
  • cd !$ esegue cd sull'ultimo argomento del comando precedente.
  • Stampa Up per richiamare la precedente riga di comando, quindi modificarla per cambiare mkdir in cd.

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

mkdir longtitleproject && cd $_

Il $_ 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.

Uso cd $_ per recuperare l'ultimo argomento del comando precedente anziché cd !$ perché cd !$ fornisce l'ultimo argomento del comando precedente nella cronologia Shell:

cd ~/
mkdir folder && cd !$

finisci a casa (o ~ /)

cd ~/
mkdir newfolder && cd $_

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

151
Jesús Carrera

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 era l'unico file nella cartella un doppio veloce TAB ti darebbe la nuova directory senza reinserirla.

Anche se è 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 manchi la sintattica zucchero fornito dagli script personalizzati.

30
Rob

Come da 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à.

17
Mikel

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.

16
Jordan Harris

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

3
sakisk

Ho creato uno script che crea la directory e quindi i cd, quindi gli ho dato un alias. Ed ecco un Gist dove lo descrivo.

https://Gist.github.com/rehnen/34236d6ff270ccaa74b6#mkdir-like-it-was-meant-to-be

0
Marcus Rehn

Ecco una leggera variante che è degna di menzione:

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

Aggiungi questo al tuo ~/.bash_profile e puoi quindi utilizzare mkdir come di consueto (una volta che hai source 'd it), tranne ora che eseguirà la funzione sopra anziché il comando standard mkdir .

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

Dai documenti (parafrasando leggermente):

command mkdir [args] esegue mkdir con args ignorando qualsiasi funzione Shell denominata mkdir. Vengono eseguiti solo i comandi incorporati Shell o i comandi trovati cercando nel PERCORSO. Se esiste una funzione Shell denominata ls, in esecuzione command ls all'interno della funzione eseguirà il comando esterno ls invece di chiamare la funzione in modo ricorsivo

Credo che builtin ottenga un risultato simile a command.

0
Arj

Aggiunta della funzione di supporto a BASH, ZSH o KSH

Crea il comando mkcd sul tuo ambiente in una riga

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