Ich kann nicht sagen, wie oft ich mir einen Befehl gewünscht habe, der sowohl ein Verzeichnis erstellt als auch in dieses Verzeichnis wechselt. Grundsätzlich hätte ich gerne das Äquivalent von:
mkdir -p /arbitrarily/long/path; cd /arbitrarily/long/path
aber nur einmal eingeben zu müssen /arbitrarily/long/path
, so etwas wie:
mk-cd /arbitrarily/long/path
Ich habe versucht, ein Skript dafür zu erstellen, aber es ändert nur das Verzeichnis innerhalb des Skripts. Ich möchte, dass sich auch das Verzeichnis in der Shell geändert hat.
#!/bin/bash
mkdir $1
cd $1
export PWD=$PWD
Wie könnte ich das schaffen?
cd
haben Sie von Anfang an einen Sonderfall ausgewählt. : Dcd
Informationen (kehren Sie zum vorherigen Verzeichnis zurückcd -
und verwenden Siepushd
undpopd
, um einen "Stapel" von Verzeichnissen zu verwalten): superuser.com/questions/324512/…mkdir -p /very/long/path
und dann verwendencd
und dann Alt + drücken.
, um das letzte Argument, dh den Namen des Verzeichnisses, zu wiederholen.mkdir -p /very/long/path; cd !#:2
. Die Zeichenfolge!#:2
wird zu Argument nr erweitert. 2 (das dritte Argument/very/long/path
, da die Zählung mit Null beginnt).!$
. Ich benutze diesen besonderen Trick die ganze Zeit, obwohl es viel mehr gibt, was Sie mit der Erweiterung der Geschichte tun können .Antworten:
Der einfachste Weg ist die Verwendung einer Shell-Funktion:
Fügen Sie es in Ihre
.bashrc
Datei ein, damit es Ihnen wie ein anderer Shell-Befehl zur Verfügung steht.Der Grund, warum es nicht als externes Skript funktioniert, liegt darin
cd
, dass das aktuelle Verzeichnis des ausgeführten Skripts geändert wird, das aufrufende jedoch nicht betroffen ist. Dies ist beabsichtigt! Jeder Prozess verfügt über ein eigenes Arbeitsverzeichnis, das von seinen untergeordneten Prozessen geerbt wird. Das Gegenteil ist jedoch nicht möglich.Sofern ein Teil einer Pipeline nicht im Hintergrund oder explizit in einer Subshell ausgeführt wird, wird eine Shell-Funktion nicht in einem separaten Prozess, sondern in demselben Prozess ausgeführt, genau wie wenn der Befehl aus einer Quelle stammt. Die aktuelle Verzeichnis-Shell kann dann durch eine Funktion geändert werden.
Das
&&
hier zum Trennen der beiden Befehle verwendete bedeutet, wenn der erste Befehl erfolgreich ist (mkdir
), führen Sie den zweiten aus (cd
). Wennmkdir
daher das angeforderte Verzeichnis nicht erstellt werden kann, ist es sinnlos, darauf zuzugreifen. Eine Fehlermeldung wird von gedrucktmkdir
und das wars.Die mit verwendete
-p
Optionmkdir
weist dieses Dienstprogramm an, ein fehlendes Verzeichnis zu erstellen, das Teil des vollständigen Pfads des als Argument übergebenen Verzeichnisnamens ist. Ein Nebeneffekt ist, dass, wenn Sie ein bereits vorhandenes Verzeichnis erstellen möchten, diemkcd
Funktion nicht fehlschlägt und Sie in diesem Verzeichnis landen. Dies kann als Problem oder Merkmal angesehen werden. Im ersteren Fall kann die Funktion beispielsweise so geändert werden, dass der Benutzer lediglich gewarnt wird:Ohne die
-p
Option wäre das Verhalten der Ausgangsfunktion sehr unterschiedlich gewesen.Wenn das Verzeichnis mit dem zu erstellenden Verzeichnis noch nicht vorhanden ist,
mkdir
schlägt die Funktion fehl.Wenn das zu erstellende Verzeichnis bereits vorhanden ist,
mkdir
schlägt dies ebenfalls fehl undcd
wird nicht aufgerufen.Beachten Sie schließlich, dass das Setzen / Exportieren
PWD
sinnlos ist, da die Shell dies bereits intern tut.Bearbeiten: Ich habe die
--
Option zu beiden Befehlen für die Funktion hinzugefügt , damit ein Verzeichnisname mit einem Bindestrich beginnt.quelle
~/.bashrc
einem der anderen Initialisierungsskripten hinzugefügt wird .alias mk-cd 'mkdir -p \!:1; cd \!:1'
ohne Funktion auszuführen ? Oder sollte ich mir Bash-Funktionen eher als erweiterte Aliase vorstellen?csh
Übergabemechanismus für Argumente ist nicht mit Aliasen im Bournestil implementiert. Funktionen sind in der Tat der richtige Weg, da sie viel flexibler sind.bar
) übergeben wurden. Eine andere Möglichkeit wärehistory 1
, wie inalias mk-cd='args="$(history 1)" && args="${args#*mk-cd\ }" && mkdir -p "$args" && cd'
- zu verwenden. Dies funktioniert für das Beispiel des Fragestellers gut, ist jedoch keine allgemeine Lösung, da alle anderen Befehle in derselben Zeile (z. B. das Weiterleiten der Ausgabe) dazu führen, dass sie fehlschlagen.Ich möchte eine alternative Lösung hinzufügen.
Ihr Skript wird funktionieren , wenn Sie es mit dem aufrufen
.
odersource
Befehl ein :Wenn Sie dies tun, ist das
export
im Skript nicht erforderlich . Sie können die Eingabe.
von umgehen, indem Sie Folgendes verwendenalias
:Der Grund, warum dies funktioniert, ist, dass ein Skript normalerweise in einer Sub-Shell ausgeführt wird, sodass seine Umgebung nach Abschluss verloren geht. Der Befehl
.
(odersource
) erzwingt jedoch, dass es in der aktuellen Shell ausgeführt wird.Diese Technik kann für Kommandosequenzen nützlich sein , die für eine Funktion zu komplex sind oder die sich in der Entwicklung und werden häufig bearbeitet: einmal die
alias
in eingegeben wurde.bash_aliases
, können Sie das Skript nach Belieben ohne Neuinitialisierung bearbeiten können.Beachte das Folgende:-
Wenn Sie ein Skript schreiben, das mit dem Befehl / aufgerufen werden muss , gibt es zwei Möglichkeiten, dies sicherzustellen:
.
source
Aus irgendeinem Grund muss ein Skript, das mit
.
/ aufgerufen wird,source
nicht ausführbar sein. Entfernen Sie daher einfach diese Berechtigung, und das Skript wird entweder nicht in "$ PATH" gefunden oder gibt einen Berechtigungsfehler aus, wenn es mit einem expliziten Pfad aufgerufen wird.Alternativ kann der folgende Trick am Kopf des Skripts verwendet werden:
Dies funktioniert, weil in einer Sub-Shell
bind
eine Warnung ausgegeben wird, obwohl kein Fehlerstatus vorliegt: wird daherread
verwendet, um bei keiner Eingabe einen Fehler zu melden.quelle
.
. Ich habe. .bashrc
unzählige Male gemacht, wusste aber nicht genau was das.
macht. Ist es ähnlich zuexport
?export var
Die interne Variable wirdvar
in die Umgebung kopiert , wo sie geerbt und als Variable in eine beliebige Sub-Shell importiert wird. Dies hat jedoch keine Auswirkungen auf eine übergeordnete Shell. Normalerweise wird eine Sub-Shell erstellt, um ein Skript auszuführen, und alle Änderungen (einschließlich exportierter Variablen) gehen verloren, wenn sie abgeschlossen sind. Damit ein Skript Variablen in einer Shell setzen kann, muss es in dieser Shell ausgeführt werden. Der.
Befehl führt das Skript aus, ohne eine Sub-Shell zu erstellen. Seltsamerweise.
benötigen Skripte, die von ausgeführt werden, keine ausführbare Berechtigung..
und suchenexport
, wird der Titel dieser Frage Sie nicht dazu bringen, hier eine Antwort zu erwarten. Daher werde ich meine Antwort so lassen, wie sie ist, aber danke für Ihren Kommentar.Kein einziger Befehl, aber Sie müssen nicht den gesamten verwendeten Pfad erneut eingeben
!$
(dies ist das letzte Argument des vorherigen Befehls im Shell-Verlauf).Beispiel:
quelle
Indem Sie Aliase erstellen . Sehr beliebte Möglichkeit, eigene Befehle zu erstellen.
Sie können einen Alias im Handumdrehen erstellen:
Das ist es. Wenn Sie diesen Alias dauerhaft beibehalten möchten (nicht nur die aktuelle Sitzung), fügen Sie diesen Befehl in eine Punktdatei ein (normalerweise ~ / .bash_aliases oder ~ / .bash_profile).
quelle
Zusätzlich zu dem, was bereits vorgeschlagen wurde, möchte ich thefuck weiterempfehlen . Es ist ein Python-Framework, mit dem Sie Ihren Shell-Prozess optimieren können, indem Sie Fehler beheben. Inspiriert von diesem Tweet , müssen Sie nur Ihren konfigurierten Alias (standardmäßig
fuck
) eingeben und es wird versucht, Ihren vorherigen Befehl zu korrigieren. Eine seiner Korrekturen verhält sich wie folgt:quelle