Gibt es einen Einzeiler, mit dem ich gleichzeitig ein Verzeichnis erstellen und darin verschieben kann?

150

Ich stelle fest, dass ich viel wiederhole:

mkdir longtitleproject
cd longtitleproject

Gibt es eine Möglichkeit, dies in einer Zeile zu tun, ohne den Verzeichnisnamen zu wiederholen? Ich bin auf Bash hier.

methodofaction
quelle
1
mkdir longtitleprojectdanncd !^
user262826
Auch wurde auf askubuntu.com/q/927463/295286 und askubuntu.com/q/249314/295286
Sergiy Kolodyazhnyy

Antworten:

160

Es gibt keinen eingebauten Befehl, aber Sie können leicht eine Funktion schreiben, die mkdirdann aufruft cd:

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

Fügen Sie diesen Code in Ihre ~/.bashrcDatei ein (oder ~/.kshrcfür ksh-Benutzer oder ~/.zshrcfür zsh-Benutzer). Es definiert eine aufgerufene Funktion mkcd. "$1"wird beim Ausführen durch das Argument der Funktion ersetzt.

Diese einfache Version hat mehrere Mängel:

  • Sie können nicht gleichzeitig eine Kette von Unterverzeichnissen erstellen. Behebung: Übergeben Sie die -pOption an mkdir. (Dies kann oder auch nicht wünschenswert sein, da es das Risiko eines Tippfehler unentdeckt bleiben erhöht, zum Beispiel mkcd mydierctory/newsubwird gerne erstellen mydierctoryund mydierctory/newsubwenn Sie gemeint erstellen newsubinnerhalb des bestehenden mydirectory.)
  • Wenn das Argument beginnt mit , -ist aber nicht nur -dann mkdirund cdwird es als Option interpretieren. Wenn es nur so ist -, cdwird es so interpretiert, dass es bedeutet $OLDPWD. Wenn es +von 0 oder mehr Ziffern gefolgt wird, cdwird es in zsh als Index im Verzeichnisstapel interpretiert. Sie können das erste Problem beheben, aber nicht die beiden anderen, indem Sie --vor dem Argument übergeben. Sie können all diese Probleme beheben ./, indem Sie dem Argument voranstellen , wenn es sich um einen relativen Pfad handelt.
  • mkdirfolgt nicht CDPATH, cdtut es aber. Wenn Sie also CDPATHeinen Wert festgelegt haben, der nicht beginnt .(eine zugegebenermaßen etwas ungewöhnliche Konfiguration), werden Sie cdmöglicherweise in ein anderes Verzeichnis als das gerade erstellte gebracht. Das Voranstellen ./auf relative Pfade behebt dieses Problem (es wird CDPATHignoriert).
  • Wenn dies mkdirfehlschlägt, wird versucht, es auszuführen cd. Fix: Verwenden Sie &&diese Option, um die beiden Befehle zu trennen.

Immer noch ziemlich einfach:

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

Diese Version hat immer noch das Potenzial, cdin ein anderes Verzeichnis zu wechseln als das, das mkdirgerade in einem Randfall erstellt wurde: Wenn das Argument to einen symbolischen Link mkcdenthält ..und durchläuft. Wenn zum Beispiel das aktuelle Verzeichnis eine symbolische Verknüpfung zu ist /tmp/hereund mylinkist /somewhere/else, mkdir mylink/../foowird /somewhere/else/foowährenddessen eine cd mylink/../fooÄnderung in erstellt foo. Es reicht nicht aus, im Argument nach symbolischen Links zu suchen, da die Shell auch symbolische Links in ihrem eigenen aktuellen Verzeichnis verfolgt und daher cd /tmp/mylink; mkdir ../foo; cd ../foonicht in das neue Verzeichnis ( /somewhere/else/foo), sondern in wechselt /tmp/foo. Ein Fix für dieses cdProblem besteht darin, zuerst alle Pfadkomponenten auflösen zu lassen ..(es ist nicht sinnvoll, foo/..if zu verwendenfooexistiert nicht, muss also mkdirnie gesehen werden ..).

Wir kommen zu dieser robusten, wenn auch etwas blutigen Version:

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
}

(Übung: Warum verwende ich beim ersten cdAufruf eine Subshell ?)

Wenn mkdir fehlschlägt, möchte ich sicher sein, das aktuelle Verzeichnis nicht zu ändern. Das Zurückwechseln mit cd - oder $ OLDPWD ist nicht gut genug, wenn die Shell nicht berechtigt ist, in ihr aktuelles Verzeichnis zu wechseln. Wenn Sie cd updates OLDPWD aufrufen, möchten wir dies nur einmal tun (oder OLDPWD wiederherstellen).


Es gibt auch weniger spezialisierte Möglichkeiten, das Wort aus der vorherigen Zeile nicht erneut eingeben zu müssen:

  • Geben Sie cd dann Esc .(oder Alt+ .) ein, um das letzte Argument aus dem vorherigen Befehl einzufügen.
  • cd !$Führt cddas letzte Argument des vorherigen Befehls aus.
  • Drücken Sie Updie vorherige Befehlszeile zu erinnern, dann bearbeiten , sie zu ändern mkdirin cd.
Gilles
quelle
Vielen Dank! das Esc. scheint mir am bequemsten zu sein, hat die Tastenfolge eine spezielle Bedeutung?
Methodofaction
Es ist nur die Bash- Sequenz (und von ihr geerbt kshund funktioniert auch in dieser zshReihenfolge) für "das letzte Wort des vorherigen Befehls wiederholen". Ich benutze es ziemlich oft.
Geekosaurier
31
@ Gilles Ich fange an zu glauben, dass der "Gilles" -Account tatsächlich von einer Expertengruppe geteilt wird. ;-)
Keith
@StephaneChazelas /a/b/..//würde eigentlich funktionieren aber nicht /a/b/../c. Fest. Ich habe die Frage einem breiteren Publikum gestellt.
Gilles
1
mkcd() { mkdir -p "$1" && cd "$1"; }scheint in (meiner Instanz von) zsh kein Problem zu sein. 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(Beinhaltet das Setup und) zeigt an /tmp/here/foo, was erstellt wurde (und was ich erwartet habe). bashfälschlicherweise erstellt und ändert /var/tmp/somewhere/foo.
Adam Katz
134

Dies ist der Einzeiler, den Sie brauchen. Keine weitere Konfiguration erforderlich:

mkdir longtitleproject && cd $_

Die $_Variable in Bash ist das letzte Argument, das dem vorherigen Befehl übergeben wurde. In diesem Fall der Name des gerade erstellten Verzeichnisses. Wie erklärt 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.

Verwenden Sie cd $_das letzte Argument des vorherigen Befehls statt abzurufen , cd !$da cd !$gibt das letzte Argument des vorherigen Befehls in der Shell - Geschichte :

cd ~/
mkdir folder && cd !$

Sie landen zu Hause (oder ~ /)

cd ~/
mkdir newfolder && cd $_

Sie landen in Newfolder unter zu Hause! (oder ~ / newfolder)

Jesús Carrera
quelle
23
Warum in
aller Welt
1
@JSmyth Ich stimme zu, dies ist ein Einzeiler, der native Shell-Funktionalität verwendet
sming
Ich denke, das OP versucht, die beiden Befehle zu vermeiden. Diese Antwort ist (fast) so gültig wie "Doing" mkdir foo && cd foo, was nicht praktisch ist.
Josemigallas
7
Das OP fragt nach einem Einzeiler, bei dem der Verzeichnisname nicht wiederholt werden muss, und das ist es
Jesús Carrera,
Dies ist der traditionelle Einzeiler, auf den Sie sich beziehen oder den andere in Dokumenten / Tutorials verwendet haben. Hier gibt es tatsächlich 3 perfekte Antworten. Dieser, der von @ jordan-harris, und die ausgewählte Antwort. Hängt von Ihrem Setup und Ihren Vorlieben ab.
Wade
30

Es wäre mir nie in den Sinn gekommen, dieses Verhalten zu skripten, da ich fast stündlich Folgendes eingebe ...

$ mkdir someDirectory<ENTER>
$ cd !$

wo bash freundlicherweise !$mit dem letzten Wort der letzten Zeile ersetzt; dh der lange Verzeichnisname, den Sie eingegeben haben.

Darüber hinaus ist die Dateinamenergänzung in solchen Situationen Ihr Freund. Wenn Ihr neues Verzeichnis die einzige Datei im Ordner ist, erhalten Sie durch ein schnelles Doppelklicken TABdas neue Verzeichnis, ohne es erneut einzugeben.

Obwohl es cool ist, dass Sie mit bash so häufige Aufgaben wie in den anderen Antworten beschrieben skripten können, ist es meiner Meinung nach besser, die Befehlszeilen-Bearbeitungsfunktionen von bash zu erlernen, damit Ihnen bei der Arbeit auf einem anderen Computer die Syntax nicht entgeht Zucker, den Ihre benutzerdefinierten Skripte bieten.

rauben
quelle
1
Gibt es einen guten Ort, um sich über die wichtigsten Bash-Macken wie diese zu informieren?
dominicbri7
@ dominicbri7 kommt in der Regel unter „bash - Befehlszeilenbearbeitung“ googeln die folgenden als Top - Ergebnis gleichen gibt web.mit.edu/gnu/doc/html/features_7.html Genauer gesagt! ist $ ein Beispiel für ein Wort Designator sehen Gnu. org / software / bash / manual / bashref.html # Word-Designators
Rob
17

Wie pro Welche Anpassungen haben Sie auf Ihrem Shell - Profil getan Produktivität zu erhöhen? , so mache ich es:

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

Dies bedeutet, dass es auch funktioniert, wenn das Verzeichnis bereits vorhanden ist.

Mikel
quelle
4
Die -pOption zu mkdir wird Fehler unterdrücken.
Glenn Jackman
1
mcd ist ein bereits vorhandener Befehl. Obwohl Sie gerade ein Beispiel gegeben haben, habe ich es selbst verwendet, da es ein Buchstabe ist, der kürzer als mkcd ist.
Dharmit
@Dharmit Shah: Was ist der vorhandene mcdBefehl? Welches Paket oder Projekt bietet diesen Befehl?
Mikel
2
mtools stellt den Befehl mcd zur Verfügung. Auf der Manpage steht "Der Befehl mcd wird verwendet, um das mtools-Arbeitsverzeichnis auf der MS-DOS-Festplatte zu ändern."
Dharmit
13

Wenn Sie Oh My Zsh verwenden, gibt es einen Befehl namens take , der genau dies ausführt . Es würde ungefähr so ​​aussehen.

take myfolder

Das habe ich eigentlich zufällig gefunden. Ich habe gerade nachgesehen und es ist auf diesem Cheat aus dem Oh My Zsh GitHub Wiki aufgelistet. Es ist ein ziemlich nützlicher Befehl und anscheinend sehr einfach, sich selbst zu erstellen.

Jordan Harris
quelle
1
Ich wusste nie über take:) Perfekt! Übrigens - iTerm2 mit Oh My Zsh. Hier gibt es tatsächlich 3 perfekte Antworten. Dieser, der von @ jesús-carrera, und die ausgewählte Antwort. Hängt von Ihrem Setup und Ihren Vorlieben ab.
Wade
3

Oder Sie können einfach eine kurze Variable im x = longproject ; mkdir $x ; cd $xlaufenden Betrieb erstellen und zweimal verwenden - was zugegebenermaßen immer noch länger ist als die Verwendung einer Shellscript-Funktion :)

Sakisk
quelle
0

Hier eine kleine Variante, die es zu erwähnen gilt:

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

Fügen Sie dies zu Ihrem hinzu ~/.bash_profileund Sie können es dann mkdirwie gewohnt verwenden (sobald Sie es sourcegetan haben), außer jetzt wird die obige Funktion anstelle des Standardbefehls mkdirausgeführt.

Beachten Sie, dass hierdurch keine Eingaben gemäß der von Gilles akzeptierten Antwort validiert werden , sondern nur demonstriert wird, wie Sie Builtins (effektiv) überschreiben können.

Aus den Dokumenten (leicht umschrieben):

command mkdir [args]Läuft mkdirunter argsIgnorierung der genannten Shell-Funktionen mkdir. Es werden nur Shell-Befehle oder Befehle ausgeführt, die beim Durchsuchen des PFADS gefunden wurden. Wenn eine Shell-Funktion mit dem Namen vorhanden ist ls, führt command lsdie Ausführung innerhalb der Funktion den externen Befehl aus, lsanstatt die Funktion rekursiv aufzurufen

Ich glaube builtinerzielt ein ähnliches Ergebnis wie command.

Arj
quelle
Sie sollten auf jeden Fall zitieren$dir
Jeff Schaller
@ Jeff, einverstanden, aber die akzeptierte Antwort hat alle Validierung, die man brauchen würde. Ich präsentiere nur die Verwendung von commandals Alternative.
Arj
0

Hinzufügen von Hilfsfunktionen zu BASH, ZSH oder KSH

Erstellen mkcdSie in einer Zeile einen Befehl für Ihre Umgebung

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

Die obigen Antworten wurden einfach automatisiert und ein einmaliges ausführbares Skript erstellt:

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

echo "$fun" >> ~/.bashrc

Kopieren Sie dies einfach in eine neue Datei mkcd.shund führen Sie es nur einmal im Terminal durch bash mkcd.sh. Führen Sie dann aus source ~/.bashrc, damit es in der aktuellen Sitzung funktioniert.

Danach können Sie mit mkcd some_dirdas Verzeichnis erstellen und direkt eingeben.

subtleseeker
quelle
Sie schlagen vor, ein Skript (in einer Datei) zu schreiben, dessen einziger Zweck darin besteht, an die ~/.bashrcDatei anzuhängen (mit einer bereits gegebenen Antwort)? Und wie schlagen Sie vor, dieses mkcd.shSkript zu erstellen ? Vielleicht mit einem Redakteur? Das sieht nach mehr Arbeit als nur Bearbeitung aus ~/.bashrc. Welchen Vorteil hat dies gegenüber der akzeptierten Antwort? …………………………………………………………………………………………………………………………………………………………………….
Scott
Es tut mir leid zu sagen, aber als ich in meiner Antwort schrieb, habe ich die obigen Antworten verwendet. Es funktioniert. Wenn Sie mir nicht glauben, versuchen Sie es. Und um es nicht zu versuchen, habe ich heute meinen ganzen Tag damit verbracht, solche Skripte in Bash und Python zu schreiben.
subtleseeker
Ich habe versucht, was Sie geschrieben haben. Es ist nicht zu arbeiten.
Scott