Je me retrouve à répéter beaucoup de:
mkdir longtitleproject
cd longtitleproject
Existe-t-il un moyen de le faire sur une seule ligne sans répéter le nom du répertoire? Je suis bash ici.
Il n'y a pas de commande intégrée, mais vous pouvez facilement écrire une fonction qui appelle mkdir
puis cd
:
mkcd () {
mkdir "$1"
cd "$1"
}
Mettez ce code dans votre ~/.bashrc
fichier (ou ~/.kshrc
pour les utilisateurs de ksh, ou ~/.zshrc
pour les utilisateurs de zsh). Il définit une fonction appelée mkcd
. "$1"
sera remplacé par l'argument de la fonction lorsque vous l'exécuterez.
Cette version simple présente plusieurs défauts:
-p
option pour mkdir
. (Cela peut être souhaitable ou non, car cela augmente le risque qu'une faute de frappe ne soit pas détectée, par exemple mkcd mydierctory/newsub
créera avec plaisir mydierctory
et mydierctory/newsub
lorsque vous vouliez créer newsub
à l'intérieur du mydirectory
.) existant-
mais pas seulement -
, puis mkdir
et cd
l'interpréteront comme une option. Si c'est juste -
, puis cd
l'interprétera comme signifiant $OLDPWD
. Si c'est +
suivi de 0 ou plusieurs chiffres, puis cd
dans zsh l'interprétera comme un index dans la pile de répertoires. Vous pouvez résoudre le premier problème, mais pas les deux autres, en passant --
avant l'argument. Vous pouvez résoudre tous ces problèmes en ajoutant ./
à l'argument s'il s'agit d'un chemin relatif.mkdir
ne suit pas CDPATH
, mais cd
le fait, donc si vous avez défini CDPATH
sur une valeur qui ne commence pas par .
(une configuration certes quelque peu inhabituelle), alors cd
peut vous amener dans un répertoire différent de celui qui vient d'être créé. Prepending ./
aux chemins relatifs corrige cela (cela fait ignorer CDPATH
).mkdir
échoue, il essaie d'exécuter cd
. Correction: utilisez &&
pour séparer les deux commandes.Encore assez simple:
mkcd () {
case "$1" in /*) :;; *) set -- "./$1";; esac
mkdir -p "$1" && cd "$1"
}
Cette version a encore le potentiel de faire entrer cd
dans un répertoire différent de celui que mkdir
vient de créer dans un cas Edge: si l'argument de mkcd
contient ..
et passe par un lien symbolique. Par exemple, si le répertoire actuel est /tmp/here
et mylink
est un lien symbolique vers /somewhere/else
, puis mkdir mylink/../foo
crée /somewhere/else/foo
tandis que cd mylink/../foo
se transforme en foo
. Il ne suffit pas de rechercher des liens symboliques dans l'argument, car le Shell suit également les liens symboliques dans son propre répertoire actuel, donc cd /tmp/mylink; mkdir ../foo; cd ../foo
ne se transforme pas dans le nouveau répertoire (/somewhere/else/foo
) mais en /tmp/foo
. Un correctif consiste à laisser le cd
intégré résoudre tout ..
les composants de chemin d'abord (cela n'a pas de sens d'utiliser foo/..
si foo
n'existe pas, donc mkdir
n'a jamais besoin de voir ..
).
Nous arrivons à cette version robuste mais légèrement sanglante:
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
}
(Exercice: pourquoi j'utilise un sous-shell pour le premier cd
appel?)
Si mkdir échoue, je veux être sûr de ne pas changer le répertoire courant. Revenir en arrière avec cd - ou $ OLDPWD n'est pas suffisant si le shell n'a pas la permission de changer dans son répertoire actuel. En outre, l'appel de cd met à jour OLDPWD, nous ne voulons donc le faire qu'une seule fois (ou restaurer OLDPWD).
Il existe également des moyens moins spécialisés pour ne pas avoir à retaper le mot de la ligne précédente:
cd
, puis Esc. (ou Alt+.) pour insérer le dernier argument de la commande précédente.cd !$
exécute cd
sur le dernier argument de la commande précédente.mkdir
en cd
.C'est la doublure dont vous avez besoin. Aucune autre configuration nécessaire:
mkdir longtitleproject && cd $_
Le $_
variable, en bash, est le dernier argument donné à la commande précédente. Dans ce cas, le nom du répertoire que vous venez de créer. Comme expliqué dans 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.
Utilisation cd $_
pour récupérer le dernier argument de la commande précédente au lieu de cd !$
parce que cd !$
donne le dernier argument de la commande précédente dans l'historique Shell:
cd ~/
mkdir folder && cd !$
vous vous retrouvez à la maison (ou ~ /)
cd ~/
mkdir newfolder && cd $_
vous vous retrouvez dans un nouveau dossier sous la maison !! (ou ~/newfolder)
Il ne me serait jamais venu à l'esprit d'écrire ce comportement parce que j'entre les informations suivantes toutes les heures ...
$ mkdir someDirectory<ENTER>
$ cd !$
où bash remplace gentiment !$
avec le dernier mot de la dernière ligne; c'est-à-dire le nom de répertoire long que vous avez entré.
De plus, l'achèvement du nom de fichier est votre ami dans de telles situations. Si votre nouveau répertoire était le seul fichier du dossier, un double rapide TAB vous donnerait le nouveau répertoire sans le ressaisir.
Bien que ce soit cool que bash vous permette de créer des scripts pour des tâches courantes comme les autres réponses le suggèrent, je pense qu'il est préférable d'apprendre les fonctionnalités d'édition de ligne de commande que bash a à offrir afin que lorsque vous travaillez sur une autre machine, vous ne manquez pas la syntaxe sucre que vos scripts personnalisés fournissent.
Selon Quelles personnalisations avez-vous faites sur votre profil Shell pour augmenter la productivité? , voici comment je le fais:
# make a directory and cd to it
mcd()
{
test -d "$1" || mkdir "$1" && cd "$1"
}
cela signifie qu'il fonctionne également si le répertoire existe déjà.
Si vous utilisez Oh My Zsh, il existe une commande appelée take qui fait exactement cela. Cela ressemblerait à quelque chose comme ça.
take myfolder
J'ai trouvé celui-ci par accident. Je viens de regarder et il est répertorié sur ce cheatsheat du wiki Oh My Zsh GitHub. C'est une commande assez utile et apparemment très facile à créer vous-même.
Ou vous pouvez simplement créer une variable courte à la volée et l'utiliser deux fois x = longproject ; mkdir $x ; cd $x
- ce qui, je l'avoue, est encore plus long que l'utilisation d'une fonction shellscript :)
J'ai fait un script qui crée le répertoire et ensuite les cd, puis je lui ai donné un alias. Et voici un Gist où je le décris.
https://Gist.github.com/rehnen/34236d6ff270ccaa74b6#mkdir-like-it-was-meant-to-be
Voici une légère variante qui mérite d'être mentionnée:
function mkdir() {
local dir=$1
command mkdir "$dir" && cd "$dir"
}
Ajoutez ceci à votre ~/.bash_profile
et vous pouvez ensuite utiliser mkdir
comme d'habitude (une fois que vous l'avez source
'), sauf que maintenant il exécutera la fonction ci-dessus plutôt que la commande standard mkdir
.
Remarque, cela ne valide pas l'entrée conformément à l'acceptation réponse de Gilles , mais montre comment vous pouvez (efficacement) remplacer les commandes intégrées.
D'après la documentation (paraphrasant légèrement):
command mkdir [args]
exécutemkdir
avecargs
en ignorant toute fonction Shell nomméemkdir
. Seules les commandes intégrées de Shell ou les commandes trouvées en recherchant le PATH sont exécutées. S'il existe une fonction Shell nomméels
, l'exécution decommand ls
dans la fonction exécutera la commande externels
au lieu d'appeler la fonction récursivement
Je crois que builtin
obtient un résultat similaire à command
.
Créez la commande mkcd
dans votre environnement en une seule ligne
echo -e 'mkcd() {\n mkdir -p "$1" && cd $_\n}' >> ~/.${0//-/}rc && . ~/.${0//-/}rc