Existe-t-il un one-liner qui me permet de créer un répertoire et d’y accéder simultanément?

150

Je me retrouve à répéter beaucoup de:

mkdir longtitleproject
cd longtitleproject

Est-il possible de le faire en une seule ligne sans répéter le nom du répertoire? Je suis sur bash ici.

méthodofaction
la source
2
Lié (mais plus général): Exécutez deux commandes sur un argument (sans script) .
G-Man
1
mkdir longtitleprojectensuitecd !^
user262826
A également été couvert sur askubuntu.com/q/927463/295286 et askubuntu.com/q/249314/295286
Sergiy Kolodyazhnyy

Réponses:

160

Il n'y a pas de commande intégrée, mais vous pouvez facilement écrire une fonction qui appelle mkdiralors cd:

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

Mettez ce code dans votre ~/.bashrcfichier (ou ~/.kshrcpour les utilisateurs de ksh, ou ~/.zshrcpour 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écutez.

Cette version simple a plusieurs défauts:

  • Vous ne pouvez pas créer une chaîne de sous-répertoires à la fois. Correction: passer l' -poption à 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/newsubcréera avec bonheur mydierctoryet mydierctory/newsubquand vous avez l'intention de créer newsubà l'intérieur de l'existant mydirectory.)
  • Si l'argument commence par -mais n'est pas juste -, alors mkdiret cdl'interprétera comme une option. Si c'est juste -, alors cdl'interprétera comme signifiant $OLDPWD. S'il est +suivi d'au moins 0 chiffres, cdin 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 un préfixe ./à l'argument s'il s'agit d'un chemin relatif.
  • mkdirne suit pas CDPATH, mais le cdfait, donc si vous avez défini CDPATHune valeur qui ne commence pas par .(une configuration certes quelque peu inhabituelle), puis cdpeut vous amener à un autre répertoire que celui qui vient d'être créé. Le fait de prévoir ./des chemins relatifs résout ce problème (cela entraîne CDPATHl’ignorance).
  • Si mkdiréchoue, il essaie de s'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 toujours le potentiel de faire cdaller dans un répertoire différent de celui qui mkdirvient d'être créé dans un cas particulier: si l'argument à mkcdcontient ..et passe par un lien symbolique. Par exemple, si le répertoire en cours est /tmp/hereet mylinkest un lien symbolique vers /somewhere/else, mkdir mylink/../foocrée /somewhere/else/fooalors la cd mylink/../foomodification 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. Par conséquent, cd /tmp/mylink; mkdir ../foo; cd ../foone changez pas dans le nouveau répertoire ( /somewhere/else/foo) mais dans /tmp/foo. Une solution à ce problème consiste à laisser l’ cdintégré résoudre tous les ..composants du chemin d’abord (cela n’a aucun sens de l’utiliser foo/..sifoon'existe pas, donc mkdirjamais besoin d'en voir ..).

Nous arrivons à cette version robuste si légèrement gore:

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 est-ce que j'utilise un sous-shell pour le premier cdappel?)

Si mkdir échoue, je veux être sûr de ne pas changer le répertoire actuel. Revenir avec cd - ou $ OLDPWD ne suffit pas si le shell n’est pas autorisé à changer de répertoire. De plus, 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:

  • Tapez cd , puis Esc .(ou Alt+ .) pour insérer le dernier argument de la commande précédente.
  • cd !$s'exécute cdsur le dernier argument de la commande précédente.
  • Appuyez sur Uppour rappeler la ligne de commande précédente, puis le modifier pour changer mkdiren cd.
Gilles
la source
Merci! l'esc. semble la plus pratique pour moi, la séquence de touches at-elle une signification particulière?
methodofaction
C'est juste la séquence Bash (et héritée de ksh, et fonctionne également zsh) pour "répéter le dernier mot de la commande précédente". Je l'utilise assez souvent.
geekosaur
31
@ Gilles Je commence à penser que le compte "Gilles" est en fait partagé par un groupe d'experts. ;-)
Keith
@ StephaneChazelas /a/b/..//fonctionnerait réellement mais pas /a/b/../c. Fixé. J'ai posé la question à un public plus large.
Gilles
1
mkcd() { mkdir -p "$1" && cd "$1"; }ne semble pas être un problème dans (mon instance 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(inclut la configuration et) affiche /tmp/here/fooce qui a été créé (et ce à quoi je m'attendais). bashcrée par erreur et passe à /var/tmp/somewhere/foo.
Adam Katz
134

C'est le one-liner dont vous avez besoin. Aucune autre configuration nécessaire:

mkdir longtitleproject && cd $_

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

Utilisez 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 du shell :

cd ~/
mkdir folder && cd !$

vous finissez chez vous (ou ~ /)

cd ~/
mkdir newfolder && cd $_

vous vous retrouvez dans newfolder sous home !! (ou ~ / nouveau dossier)

Jesús Carrera
la source
23
Pourquoi sur terre, ce n'est pas la réponse acceptée
JSmyth
1
@JSmyth Je suis d'accord, c'est une ligne qui utilise les fonctionnalités du shell natif
sming
Je pense que le PO essaie d'éviter d'utiliser les deux commandes. Cette réponse est (presque) aussi valable que le faire mkdir foo && cd foo, ce qui n’est pas pratique.
josemigallas
7
L'OP demande une seule ligne qui ne nécessite pas de répéter le nom du répertoire, et ce qu'il est
Jesús Carrera
C’est le one-liner traditionnel auquel vous faites référence ou que vous avez vu d’autres utiliser dans les docs / tutoriels. Il y a en fait 3 réponses parfaites ici. Celui-ci, celui de @ jordan-harris et la réponse sélectionnée. Cela dépend de votre configuration et de vos préférences.
Wade
30

Je n'aurais jamais imaginé créer un scénario pour ce comportement, car j'entre ce qui suit presque toutes les heures ...

$ mkdir someDirectory<ENTER>
$ cd !$

où bash substitue gentiment !$le dernier mot de la dernière ligne; c'est-à-dire le nom de répertoire long que vous avez entré.

En outre, 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 TABvous donnerait le nouveau répertoire sans le saisir à nouveau.

Bien que ce soit cool que bash vous permette de créer des tâches courantes comme le suggèrent les autres réponses, je pense qu'il est préférable d’apprendre les fonctionnalités de modification de la ligne de commande que bash a à offrir afin que, lorsque vous travaillez sur une autre machine, vous ne manquiez pas de syntaxe. sucre que vos scripts personnalisés fournissent.

Rob
la source
1
Y a-t-il un bon endroit pour en savoir plus sur les plus importantes bizarreries bash comme celle-ci?
dominicbri7
@ dominicbri7 est généralement dans « l' édition de ligne de commande bash » googler même donne ce qui suit comme un bon résultat web.mit.edu/gnu/doc/html/features_7.html Plus précisément,! $ est un exemple d'un mot désignateur voir gnu. org / software / bash / manual / bashref.html # Word-Designators
Rob
17

Selon quelles personnalisations avez-vous effectuées sur votre profil de coque 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 que cela fonctionne aussi si le répertoire existe déjà.

Mikel
la source
4
L' -poption mkdir supprimera les erreurs.
Glenn Jackman
1
mcd est une commande déjà existante. Bien que vous veniez de donner un exemple, je l'ai utilisé moi-même, car il s'agit d'une lettre plus courte que mkcd.
Dharmit
@Dharmit Shah: Quelle est la mcdcommande existante ? Quel paquet ou projet fournit cette commande?
Mikel
2
mtools fournit la commande mcd. Sa page de manuel indique "La commande mcd est utilisée pour modifier le répertoire de travail mtools sur le disque MS-DOS".
Dharmit
13

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 effectivement trouvé celui-ci par accident. Je viens de regarder et il est répertorié sur cette astuce du wiki Oh My Zsh GitHub. C'est une commande assez utile, et apparemment très facile à créer vous-même.

Jordan Harris
la source
1
Je n'ai jamais su à propos de take:) Parfait! btw - iTerm2 avec Oh My Zsh. Il y a en fait 3 réponses parfaites ici. Celui-ci, celui de @ jesús-carrera et la réponse sélectionnée. Cela dépend de votre configuration et de vos préférences.
Wade
3

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 :)

Sakis
la source
0

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_profileet vous pourrez alors utiliser mkdirnormalement (une fois que vous en aurez besoin source), sauf que maintenant, la fonction ci-dessus sera exécutée plutôt que la mkdircommande standard .

Notez que cela ne valide pas les entrées conformément à la réponse acceptée par Gilles , mais montre comment vous pouvez (efficacement) écraser les éléments intégrés.

D'après la documentation (en paraphrasant légèrement):

command mkdir [args]s'exécute mkdiren argsignorant toute fonction shell nommée mkdir. Seules les commandes internes au shell ou les commandes trouvées en effectuant une recherche dans le PATH sont exécutées. S'il existe une fonction shell nommée ls, son exécution command lsexécutera la commande externe lsau lieu d'appeler la fonction de manière récursive.

Je crois que builtinréalise un résultat similaire à command.

Arj
la source
vous devriez certainement citer$dir
Jeff Schaller
@ Jeff, d'accord, mais la réponse acceptée contient toutes les validations nécessaires. Je présente simplement l'utilisation de commandcomme une alternative.
Arj
0

Ajout de la fonction d'assistance à BASH, ZSH ou KSH

Créer une mkcdcommande pour votre environnement en une seule ligne

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

Juste automatisé les réponses ci-dessus et fait un script exécutable une fois:

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

echo "$fun" >> ~/.bashrc

Il suffit de copier ceci dans un nouveau fichier mkcd.shet de ne l'exécuter qu'une seule fois dans le terminal bash mkcd.sh. Puis exécutez-le source ~/.bashrcpour le faire fonctionner dans la session en cours.

Après cela, vous pouvez utiliser mkcd some_dirpour créer et entrer directement dans ce répertoire.

subtilitaire
la source
Vous suggérez d'écrire un script (dans un fichier) dont le seul but est de l'ajouter au ~/.bashrcfichier (avec une réponse déjà donnée)? Et comment suggérez-vous de créer ce mkcd.shscript? Avec un éditeur, peut-être? Cela ressemble à plus de travail que juste l'édition ~/.bashrc. Quel avantage cela at-il sur la réponse acceptée? ………………………………………………………………… PS Cela échouera à cause de certains problèmes, ce qui me dit que vous ne l'avez même pas essayé vous-même.
Scott
Je suis désolé de le dire, mais oui, comme je l’ai écrit dans ma réponse, j’ai utilisé les réponses ci-dessus. Ça marche. Si vous ne me croyez pas, essayez-le. Et pour ne pas essayer, j’ai utilisé toute ma journée pour écrire de tels scripts aujourd’hui en bash et en python.
subtleseeker
J'ai essayé ce que tu as écrit. Ça ne marche pas .
Scott