Eseguire un comando da un'altra directory in bash


119

Dì che lo sto facendo:

cd subdir
git init
cd ../

C'è un modo per farlo con un singolo comando, o forse due, anziché dover entrare e uscire da una directory per eseguire un comando lì?

(Non cerco una soluzione specifica per git; questo è solo un esempio.)

Risposte:


202

Questo è spesso il modo migliore:

( cd dir ; git init )

o

( cd dir && git init )

È piuttosto breve e facile da scrivere. Avvia una sotto-shell, quindi non è possibile modificare il proprio ambiente da quello, ma questo non sembra essere un problema qui.


1
E se hai bisogno di impostare una o due variabili di ambiente, aggiungila all'inizio come un altro comando.
Ippopotamo,

1
@CraigMcQueen: non proprio. $?conterrà il codice di uscita dell'ultimo comando eseguito nella subshell. Se usi la &&variante (che di solito dovresti), otterrai il codice di uscita del primo comando che ha fallito (o 0 se tutto è andato bene).
Mat,

Penso che le parentesi siano opzionali
Francis.Beauchamp,

10
@ Francis.Beauchamp: se ometti le parentesi, sarai nel sottodiretto dopo il comando anziché nel punto in cui hai iniziato.
Mat

Come si fa a farlo su Windows?
Karl Morrison,

22

Stavo cercando un modo per eseguire il comando git da un percorso e apportare modifiche al repository in un percorso diverso. Quindi ho finito con questa domanda qui.

Ma per le mie esigenze specifiche né la risposta accettata né nessuna delle altre ha aiutato.

Avevo bisogno di eseguire i comandi git utilizzando sudo -u USER /usr/bin/git(un altro utente che lo esegue). E come forse sapete, sudo non mi permette di eseguire il cdcomando, quindi non posso essere nella directory repository.

Quindi, sono andato alla pagina man di git . E tra le opzioni, ho visto --git-dir=<path>:

--git-dir =

Imposta il percorso per il repository. Questo può anche essere controllato impostando la variabile d'ambiente GIT_DIR. Può essere un percorso assoluto o relativo alla directory di lavoro corrente.

Quindi, se aiuta qualcuno, puoi comunque usare git da un percorso e apportare modifiche a un repository "lontano da te". Usa solo:

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

oppure, per eseguirlo come un altro utente, fai qualcosa del tipo:

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

Anche dalla pagina man di git-init :

Se la variabile di ambiente $ GIT_DIR è impostata, specifica un percorso da utilizzare anziché ./.git per la base del repository.

Quindi, se si desidera avviare il repository nella normale cartella .git, sarà necessario specificarlo insieme --git-dirall'opzione. per esempio:

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

Dopo aver inizializzato il repository su /path/to/repo/.git, tutti gli altri comandi dovrebbero avere l'opzione --work-tree=<path>, come descritto nella pagina man di git:

--work-albero =

Imposta il percorso per l'albero di lavoro. Può essere un percorso assoluto o un percorso relativo alla directory di lavoro corrente. Questo può anche essere controllato impostando la variabile d'ambiente GIT_WORK_TREE e la variabile di configurazione core.worktree (vedi core.worktree in git-config (1) per una discussione più dettagliata).

Quindi, il comando giusto per eseguire git come un altro utente e inizializzare un nuovo repository è:

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

Se stai usando sudo in modo interattivo e non tramite uno script, potresti semplicemente fare sudo -io sudo suottenere una shell root interattiva.
Bugster,

Non riesco a immaginare perché ( cd subdir && sudo -u USER /usr/bin/git init )non funzioni.
Scott,

Cosa succede se non ho il permesso di accedere subdir?
dmmd

13

Non esattamente quello che stai chiedendo (hai risposte reali sopra con la subshell) ma guarda pushdepopd


Ho provato con cd && per Maven e non ha funzionato, ma pushd e popd funzionano perfettamente. Grazie
Radu Toader il

6

Hai alcune opzioni. Puoi raggruppare i comandi con &&o ;. Come questo:

cd subdir && git init && cd ..

o

cd subdir; git init; cd ..

La differenza tra questi è che nel primo esempio, se uno dei comandi fallisce, non eseguirà il resto di essi. Nel secondo esempio, tutti i comandi verranno eseguiti indipendentemente da cosa.

Un'altra opzione sarebbe quella di definire una funzione e usarla, ad esempio:

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

Quindi è possibile eseguire il comando:

cdinit subdir

E verrà automaticamente git initin quella directory e uscirà da essa.

Puoi anche fare una soluzione più complessa usando una funzione se hai un sacco di directory e vuoi git initfarle con un solo comando.

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

È quindi possibile eseguire questo con:

cdinit subdir1 subdir2 subdir3

E lo farà git initin subdir1, subdir2e subdir3.


Grazie. Ne ero consapevole &&e ;, ma speravo in qualcosa di più elegante. Sembra che scrivere una sceneggiatura sia la mia migliore opzione.
Trevor Burnham,

Correzione: questa risposta va bene, ma la risposta di Mat è migliore per le mie esigenze particolari.
Trevor Burnham,

Pensi che la tua cdinitfunzione possa essere generalizzata per comandi arbitrari? Ho provato a usare solo gli argomenti, ma non ha funzionato.
Chetan Bhasin,

(1) Newline è equivalente a ;, quindi la funzione a tre righe è equivalente a cd $1; git init; cd ... (2) Si dovrebbe citare le variabili: "$1", "$@"e "$arg". Oppure si può abbreviare for arg in "$@"a for arg.
Scott,

5

In caso di git(almeno nella versione 2.7.0), è possibile sfruttare l' -Copzione che fa in modo che git si comporti come se fosse stato avviato nella directory specificata. Quindi la tua soluzione potrebbe apparire come:

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

Citando la documentazione:

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

Puoi raggruppare i comandi con &&, ad es

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

Se non si desidera alcuna dipendenza dal codice di uscita di ciascun comando, è possibile utilizzare; invece, cioè:

cd subdir ; git init ; cd ../

1
O in ;modo che non dipendano dal codice di ritorno del precedente.
slhck,

(1) in  cd subdir && git init ; cd ..realtà potrebbe avere più senso. Se l'utente desidera eseguire il git initcomando in subdir, probabilmente non desidera eseguire il comando nella directory corrente; cioè, non vogliono eseguirlo se il (primo) cdfallisce. (Anche se è possibile che  cdfallisca perché siamo già in subdir, ma questo è un caso angolare.) ... (proseguendo)
Scott

(Proseguendo) ... Tuttavia, se l'utente desidera trattare il blocco di tre comandi come un'unità, potrebbe voler  cdeseguire il backup nella directory iniziale anche se il git initcomando non riesce. ( Oppure, potrebbero voler rimanere nella sottodirectory e diagnosticare l'errore del comando.) (2) Non è necessario includere il /dopo  ...
Scott,

2

Devi saltare nella tua directory di destinazione se il comando non ha un parametro nome file o directory.

Ma puoi scrivere uno script bash che accetta la directory di destinazione e il comando come parametri. Per questo puoi dare un'occhiata a pushd e popd: http://ss64.com/bash/pushd.html

Scriverei quel piccolo script per te, ma non ho una scatola Linux qui :)


Ho appena visto la risposta di Mark Szymanski. Potresti semplicemente implementare un secondo parametro per un comando (e rinominare il comando) e hai quello che vuoi.
Wullxz,

1

I programmi hanno modi diversi di gestire gli argomenti, quindi alcuni avranno l'equivalente dell'opzione -folder = name . Al di là di tale eccezione, lo standard, anche su MS DOS, è semplicemente

$ programma sottodir

A volte hai bisogno

$ programma subdir /

Il programma aprirà la cartella, funzionerà allo stesso modo in cui si lavora con un file e, una volta terminato, restituirà il controllo alla shell, che è puntata sulla directory standard originale. I programmi gestiti in questo modo hanno il problema che gli output degli errori (come i core dump) vanno in un file nella directory corrente della shell (piuttosto che nel sottodir .)

Non c'è soluzione alternativa a meno che il programma non abbia opzioni di comando disponibili per specificare una posizione diversa. Alcuni programmatori ottengono la licenza artistica tra "il programma di directory è stato chiamato da " e "al programma di directory è stato detto di funzionare ".

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.