Exécuter une commande depuis un autre répertoire dans bash


119

Dis que je fais ça:

cd subdir
git init
cd ../

Y a-t-il un moyen de faire cela avec une seule commande, ou peut-être deux, plutôt que de devoir entrer et sortir d'un répertoire pour y exécuter une commande?

(Ne cherchez pas une solution spécifique à Git, ce n'est qu'un exemple.)

Réponses:


202

C'est souvent le meilleur moyen:

( cd dir ; git init )

ou

( cd dir && git init )

C'est assez court et facile à taper. Cela démarre un sous-shell, vous ne pouvez donc pas modifier votre environnement à partir de cela, mais cela ne semble pas être un problème ici.


1
Et si vous devez définir une ou deux variables d’environnement, ajoutez-le au début comme une autre commande.
Hippo

1
@CraigMcQueen: pas vraiment. $?contiendra le code de sortie de la dernière commande exécutée dans le sous-shell. Si vous utilisez la &&variante (ce que vous devriez habituellement), vous obtiendrez le code de sortie de la première commande ayant échoué (ou 0 si tout s'est bien passé).
Mat

Je pense que les parenthèses sont facultatives
Francis.Beauchamp

10
@ Francis.Beauchamp: si vous omettez les parenthèses, vous serez dans le sous-répertoire après la commande plutôt que de revenir à l'endroit où vous avez commencé.
Mat

Comment fait-on cela sous Windows?
Karl Morrison le

22

Je cherchais un moyen d'exécuter la commande git à partir d'un chemin et d'apporter des modifications au référentiel dans un chemin différent. Donc je me suis retrouvé dans cette question ici.

Mais pour mes besoins spécifiques, ni la réponse acceptée ni aucune des autres ne m'aident.

J'avais besoin d'exécuter des commandes git en utilisant sudo -u USER /usr/bin/git(un autre utilisateur qui l'exécute). Et comme vous le savez peut-être, sudo ne me permet pas d’exécuter la cdcommande, je ne peux donc pas être dans le répertoire du référentiel.

Donc, je suis allé à la page de manuel de git . Et parmi les options, j'ai vu le --git-dir=<path>:

--git-dir =

Définissez le chemin d'accès au référentiel. Cela peut également être contrôlé en définissant la variable d’environnement GIT_DIR. Il peut s'agir d'un chemin absolu ou relatif vers le répertoire de travail actuel.

Donc, si cela aide quelqu'un, vous pouvez toujours utiliser git depuis un chemin et apporter des modifications à un dépôt "loin de vous". Il suffit d'utiliser:

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

ou, pour l'exécuter en tant qu'utilisateur différent, procédez comme suit:

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

Également sur la page de manuel de git-init :

Si la variable d'environnement $ GIT_DIR est définie, elle spécifie un chemin à utiliser à la place de ./.git pour la base du référentiel.

Ainsi, si vous souhaitez initialiser le référentiel sous le dossier .git habituel, vous devez le spécifier avec l' --git-diroption. par exemple:

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

Après l’initialisation du référentiel /path/to/repo/.git, toutes les commandes ultérieures devraient avoir l’option --work-tree=<path>, comme décrit sur la page de manuel de git:

--work-tree =

Définissez le chemin d'accès à l'arbre de travail. Il peut s'agir d'un chemin absolu ou d'un chemin relatif au répertoire de travail en cours. Cela peut également être contrôlé en définissant la variable d'environnement GIT_WORK_TREE et la variable de configuration core.worktree (voir core.worktree dans git-config (1) pour une discussion plus détaillée).

Ainsi, la bonne commande pour exécuter git en tant qu'utilisateur différent et initialiser un nouveau référentiel est la suivante:

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

Si vous utilisez sudo de manière interactive et non via un script, vous pouvez simplement le faire sudo -iou sudo suobtenir un shell racine interactif.
Bugster

Je ne peux pas imaginer pourquoi ça ( cd subdir && sudo -u USER /usr/bin/git init )ne marcherait pas.
Scott

Et si je n'ai pas la permission d'y accéder subdir?
dmmd

13

Pas exactement ce que vous demandez (vous avez les vraies réponses ci-dessus avec le sous-shell) mais regardez pushdetpopd


J'ai essayé avec cd && pour maven et cela n'a pas fonctionné, mais pushd and popd fait parfaitement l'affaire. Merci
Radu Toader

6

Vous avez quelques options. Vous pouvez grouper les commandes avec &&ou ;. Comme ça:

cd subdir && git init && cd ..

ou

cd subdir; git init; cd ..

La différence entre ceux-ci est que dans le premier exemple, si l'une des commandes échoue, elle n'exécutera pas le reste. Dans le deuxième exemple, toutes les commandes seront exécutées quoi qu'il arrive.

Une autre option serait de définir une fonction et de l’utiliser, par exemple:

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

Ensuite, vous pouvez exécuter la commande:

cdinit subdir

Et ce sera automatiquement git initdans ce répertoire et sortir de celui-ci.

Vous pouvez également faire une solution plus complexe en utilisant une fonction si vous avez plusieurs répertoires et que vous voulez les utiliser git initavec une seule commande.

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

Vous pouvez ensuite exécuter ceci avec:

cdinit subdir1 subdir2 subdir3

Et il le fera git initdans subdir1, subdir2et subdir3.


Merci. J'étais au courant &&et ;espérais quelque chose de plus élégant. On dirait que l'écriture d'un script est ma meilleure option.
Trevor Burnham

Correction: Cette réponse est correcte, mais la réponse de Mat répond mieux à mes besoins particuliers.
Trevor Burnham

Pensez-vous que votre cdinitfonction peut être généralisée pour des commandes arbitraires? J'ai essayé d'utiliser uniquement les arguments, mais cela n'a pas fonctionné.
Chetan Bhasin le

(1) Newline est équivalent à ;, de sorte que la fonction à trois lignes est équivalente à cd $1; git init; cd ... (2) Vous devez citer vos variables: "$1", "$@"et "$arg". Ou vous pouvez abrégez for arg in "$@"à for arg.
Scott

5

Dans le cas de git(au moins dans la version 2.7.0), vous pouvez utiliser l' -Coption qui fait que git se comporte comme si elle avait été démarrée dans le répertoire donné. Votre solution peut donc ressembler à:

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

Citer la documentation:

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. 

2

Vous pouvez regrouper les commandes avec &&, c.-à-d.

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

Si vous ne souhaitez aucune dépendance sur le code de sortie de chaque commande, vous pouvez utiliser; à la place, à savoir:

cd subdir ; git init ; cd ../

1
Ou avec ;pour qu'ils ne dépendent pas du code de retour du précédent.
Slhck

(1)  cd subdir && git init ; cd ..peut réellement avoir le plus de sens. Si l'utilisateur veut exécuter la git initcommande dans le subdir, il ne veut probablement pas exécuter la commande dans le répertoire en cours; c'est-à-dire qu'ils ne veulent pas l'exécuter si le (premier) cdéchoue. (Bien qu'il soit possible que cela  cdéchoue parce que nous sommes déjà dans le subdir, mais c'est un cas en coin.)… (Suite)
Scott

(Suite)… Cependant, si l'utilisateur veut traiter le bloc de trois commandes comme une unité, il peut vouloir  cdsauvegarder dans le répertoire de départ même si la git initcommande échoue. ( Ou, ils pourraient vouloir rester dans le sous - répertoire et diagnostiquer la panne de commande.) (2) Vous n'avez pas besoin d'inclure l' /après  ...
Scott

2

Vous devez accéder à votre répertoire cible si la commande n'a pas de paramètre nom de fichier ou nom de répertoire.

Mais vous pouvez écrire un script bash qui prend comme paramètres le répertoire cible et la commande. Pour cela, vous pouvez jeter un oeil à pushd et popd: http://ss64.com/bash/pushd.html

J'écrirais ce petit script pour vous, mais je n'ai pas de machine Linux ici :)


Je viens de voir la réponse de Mark Szymanski. Vous pouvez simplement implémenter un deuxième paramètre pour une commande (et renommer la commande) et vous avez ce que vous voulez.
wullxz

1

Les programmes ont différentes manières de gérer les arguments, ainsi quelques-uns auront une option équivalente de l' option -folder = name . Au-delà de cette exception, le standard, même sous MS-DOS, est simplement

$ programme subdir

Parfois vous avez besoin

$ programme subdir /

Le programme ouvrira le dossier, le travaillera de la même manière que vous le feriez avec un fichier, et une fois terminé, vous rendrez le contrôle à votre shell, qui est dirigé vers votre répertoire standard d'origine. Les programmes gérés de cette manière ont pour problème que les sorties d'erreur (telles que les vidages principaux ) sont dirigées vers un fichier du répertoire actuel de votre shell (plutôt que sous- répertoire ).

Il n'y a pas de solution de contournement à moins que le programme dispose de commutateurs de commande permettant de spécifier un emplacement différent. Certains programmeurs prennent une licence artistique entre "programme de répertoire appelé depuis " et "programme de répertoire chargé de travailler ".

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.