Führen Sie in bash einen Befehl aus einem anderen Verzeichnis aus

119

Sagen Sie, dass ich das mache:

cd subdir
git init
cd ../

Gibt es eine Möglichkeit, dies mit einem oder zwei Befehlen zu tun, anstatt in ein Verzeichnis zu wechseln und es wieder zu verlassen, um dort einen Befehl auszuführen?

(Nicht auf der Suche nach einer git-spezifischen Lösung; das ist nur ein Beispiel.)

Trevor Burnham
quelle

Antworten:

202

Dies ist oft der beste Weg:

( cd dir ; git init )

oder

( cd dir && git init )

Es ist ziemlich kurz und einfach zu tippen. Es wird eine Sub-Shell gestartet, sodass Sie Ihre Umgebung nicht daran ändern können, aber das scheint hier kein Problem zu sein.

Matte
quelle
1
Und wenn Sie eine oder zwei Umgebungsvariablen festlegen müssen, fügen Sie diese am Anfang einfach als weiteren Befehl hinzu.
Hippo
1
@CraigMcQueen: nicht wirklich. $?Enthält den Exit-Code des letzten Befehls, der in der Subshell ausgeführt wurde. Wenn Sie die &&Variante verwenden (die Sie normalerweise verwenden sollten), erhalten Sie den Exit-Code des ersten fehlgeschlagenen Befehls (oder 0, wenn alles in Ordnung war).
Mat
Ich denke, die Klammern sind optional
Francis.Beauchamp
10
@ Francis.Beauchamp: Wenn Sie die Parens weglassen, befinden Sie sich nach dem Befehl im Unterverzeichnis und nicht dort, wo Sie begonnen haben.
Mat
Wie macht man das unter Windows?
Karl Morrison
22

Ich suchte nach einer Möglichkeit, den Befehl git über einen Pfad auszuführen und Änderungen am Repository unter einem anderen Pfad vorzunehmen. Also bin ich hier auf diese Frage gekommen.

Aber für meine speziellen Bedürfnisse hat weder die akzeptierte Antwort noch eine der anderen geholfen.

Ich musste Git-Befehle mit sudo -u USER /usr/bin/git(einem anderen Benutzer, der es ausführt) ausführen . Und wie Sie vielleicht wissen, ist sudo nicht zulassen , dass ich den läuft cdBefehl, so kann ich nicht sein , im Repository - Verzeichnis.

Also ging ich zur Manpage von git . Und unter den Optionen sah ich die --git-dir=<path>:

--git-dir =

Legen Sie den Pfad zum Repository fest. Dies kann auch durch Setzen der Umgebungsvariablen GIT_DIR gesteuert werden. Dies kann ein absoluter oder relativer Pfad zum aktuellen Arbeitsverzeichnis sein.

Wenn es also jemandem hilft, können Sie immer noch git von einem Pfad verwenden und Änderungen an einem Repository "weit von Ihnen entfernt" vornehmen. Benutz einfach:

git --git-dir=/path/to/repository GIT_COMMAND

oder, um es als ein anderer Benutzer auszuführen, mache etwas wie:

echo USER_PASSWORD | sudo -u USER_LOGIN -S /usr/bin/git --git-dir=/path/to/repository GIT_COMMAND

Auch aus der Manpage von git-init :

Wenn die Umgebungsvariable $ GIT_DIR festgelegt ist, gibt sie einen Pfad an, der anstelle von ./.git für die Basis des Repositorys verwendet werden soll.

Wenn Sie das Repository also im üblichen .git-Ordner starten möchten, müssen Sie es zusammen mit der --git-dirOption angeben . z.B:

echo USER_PASSWORD | sudo -u USER_LOGIN -S /usr/bin/git --git-dir=/path/to/repository/.git init

Nach der Initialisierung des Repositorys /path/to/repo/.gitsollten alle weiteren Befehle die Option haben --work-tree=<path>, wie auf der Manpage von git beschrieben:

--work-tree =

Legen Sie den Pfad zum Arbeitsbaum fest. Dies kann ein absoluter Pfad oder ein Pfad relativ zum aktuellen Arbeitsverzeichnis sein. Dies kann auch gesteuert werden, indem die Umgebungsvariable GIT_WORK_TREE und die Konfigurationsvariable core.worktree festgelegt werden (weitere Informationen finden Sie unter core.worktree in git-config (1)).

Der richtige Befehl, um git als anderer Benutzer auszuführen und ein neues Repository zu initialisieren, lautet:

echo USER_PASSWORD | sudo -u USER_LOGIN -S /usr/bin/git --git-dir=/path/to/repository/.git init
echo USER_PASSWORD | sudo -u USER_LOGIN -S /usr/bin/git --git-dir='/path/to/repository/.git' --work-tree='/path/to/repository' add /path/to/repository/*
echo USER_PASSWORD | sudo -u USER_LOGIN -S /usr/bin/git --git-dir='/path/to/repository/.git' --work-tree='/path/to/repository' commit -m 'MESSAGE'
echo USER_PASSWORD | sudo -u USER_LOGIN -S /usr/bin/git --git-dir='/path/to/repository/.git' --work-tree='/path/to/repository' remote add origin user@domain.com:path
echo USER_PASSWORD | sudo -u USER_LOGIN -S /usr/bin/git --git-dir='/path/to/repository/.git' --work-tree='/path/to/repository' push -u origin master
dmmd
quelle
Wenn Sie sudo interaktiv und nicht durch ein Skript verwenden, können Sie einfach tun sudo -ioder sudo sueine interaktive Root - Shell zu erhalten.
Bugster
Ich kann mir nicht vorstellen, warum ( cd subdir && sudo -u USER /usr/bin/git init )das nicht funktionieren würde.
Scott
Was ist, wenn ich keine Zugriffsberechtigung habe subdir?
24.
13

Nicht genau das, was Sie fragen (Sie haben oben mit der Unterschale echte Antworten), aber schauen Sie sich pushdund anpopd

Reiche Homolka
quelle
Ich habe es mit cd && für maven versucht und es hat nicht funktioniert, aber pushd und popd machen den Job perfekt. Vielen Dank
Radu Toader
6

Sie haben ein paar Möglichkeiten. Sie können die Befehle entweder mit &&oder gruppieren ;. So was:

cd subdir && git init && cd ..

oder

cd subdir; git init; cd ..

Der Unterschied zwischen diesen ist, dass im ersten Beispiel, wenn einer der Befehle fehlschlägt, der Rest von ihnen nicht ausgeführt wird. Im zweiten Beispiel werden alle Befehle ausgeführt, egal was passiert.

Eine andere Möglichkeit wäre, eine Funktion zu definieren und zu verwenden, zum Beispiel:

function cdinit() {
    cd $1
    git init
    cd ..
}

Dann können Sie den Befehl ausführen:

cdinit subdir

Und es wird automatisch git initin dieses Verzeichnis verschoben und aus diesem entfernt.

Sie können auch eine komplexere Lösung mit einer Funktion ausführen, wenn Sie eine Reihe von Verzeichnissen haben und git initdiese mit einem einzigen Befehl aufrufen möchten .

function cdinit() {
    for arg in $@
    do
        cd $arg
        git init
        cd ..
    done
}

Sie können dies dann ausführen mit:

cdinit subdir1 subdir2 subdir3

Und es wird nicht git initin subdir1, subdir2und subdir3.

Wuffers
quelle
Vielen Dank. Ich war mir bewusst &&und ;hoffte auf etwas Eleganteres. Klingt so, als wäre das Schreiben eines Skripts meine beste Option.
Trevor Burnham
Korrektur: Diese Antwort ist in Ordnung, aber Mat's Antwort ist besser für meine besonderen Bedürfnisse.
Trevor Burnham
Denken Sie, dass Ihre cdinitFunktion für beliebige Befehle verallgemeinert werden kann? Ich habe versucht, nur die Argumente zu verwenden, aber das hat nicht funktioniert.
Chetan Bhasin
(1) Newline ist äquivalent zu ;, so dass die Dreizeilenfunktion äquivalent zu ist cd $1; git init; cd ... (2) Sie sollten Ihre Variablen zitieren: "$1", "$@"und "$arg". Oder Sie können abkürzen for arg in "$@"zu for arg.
Scott
5

Im Falle von git(zumindest in Version 2.7.0) können Sie die -COption nutzen, mit der sich git so verhält, als ob es im angegebenen Verzeichnis gestartet worden wäre. So könnte Ihre Lösung aussehen:

> git -C subdir init
Initialized empty Git repository in /some/path/subdir/.git/

Zitieren der Dokumentation:

Run as if git was started in <path> instead of the current working directory. When multiple -C options are given, each subsequent non-absolute -C
<path> is interpreted relative to the preceding -C <path>.

This option affects options that expect path name like --git-dir and --work-tree in that their interpretations of the path names would be made
relative to the working directory caused by the -C option. 
Mifeet
quelle
2

Sie können die Befehle mit && gruppieren, dh

cd subdir && git init && cd ../

Wenn Sie keine Abhängigkeit vom Exit-Code der einzelnen Befehle wünschen, können Sie Folgendes verwenden: stattdessen, dh:

cd subdir ; git init ; cd ../
Gaff
quelle
1
Oder ;damit sie nicht vom Rückkehrcode des vorherigen abhängen.
Slhck
(1)  cd subdir && git init ; cd ..kann tatsächlich am sinnvollsten sein. Wenn der Benutzer den git initBefehl in ausführen möchte, möchte er den Befehl subdirwahrscheinlich nicht im aktuellen Verzeichnis ausführen. Das heißt, sie möchten es nicht ausführen, wenn das (erste) cdfehlschlägt. (Obwohl es möglich ist, dass das  cdscheitert, weil wir bereits in der subdir, aber das ist ein Eckfall.)… (Fortsetzung)
Scott
(Fortsetzung) ... Wenn der Benutzer jedoch den Block mit drei Befehlen als eine Einheit behandeln möchte, möchte er möglicherweise auch  cddann in das Startverzeichnis zurückkehren, wenn der git initBefehl fehlschlägt. ( Oder sie möchten möglicherweise im Unterverzeichnis bleiben und den Befehlsfehler diagnostizieren.) (2) Sie müssen das /After  nicht einschließen ...
Scott
2

Sie müssen in Ihr Zielverzeichnis springen, wenn der Befehl keinen Dateinamen oder Verzeichnisnamenparameter enthält.

Sie können jedoch ein Bash-Skript schreiben, das das Zielverzeichnis und den Befehl als Parameter verwendet. Hierfür können Sie einen Blick auf pushd und popd werfen: http://ss64.com/bash/pushd.html

Ich würde dieses kleine Skript für dich schreiben, aber ich habe hier keine Linux-Box :)

wullxz
quelle
Habe gerade die Antwort von Mark Szymanski gesehen. Sie können einfach einen zweiten Parameter für einen Befehl implementieren (und den Befehl umbenennen) und haben das, was Sie wollen.
Wullxz
1

Programme haben verschiedene Möglichkeiten, mit Argumenten umzugehen . Einige Programme haben also die Option -folder = name . Abgesehen von dieser Ausnahme ist der Standard auch unter MS DOS einfach

$ program subdir

Manchmal brauchst du

$ program subdir /

Das Programm öffnet den Ordner, arbeitet damit wie mit einer Datei und gibt die Kontrolle an Ihre Shell zurück, die auf Ihr ursprüngliches Standardverzeichnis verweist. Programme, die auf diese Weise behandelt werden, haben das Problem, dass Fehlerausgaben (wie z. B. Core-Dumps) in eine Datei im aktuellen Verzeichnis Ihrer Shell (und nicht in ein Unterverzeichnis ) verschoben werden .

Es gibt keine Problemumgehung, es sei denn, das Programm verfügt über Befehlsschalter, um einen anderen Ort anzugeben. Einige Programmierer nehmen eine künstlerische Lizenz zwischen "Verzeichnisprogramm wurde aufgerufen von " und "Verzeichnisprogramm wurde angewiesen, in ".

Vlueboy
quelle