Wykonaj polecenie z innego katalogu w bash

119

Powiedz, że to robię:

cd subdir
git init
cd ../

Czy istnieje sposób, aby to zrobić za pomocą jednego polecenia, a może dwóch, zamiast wchodzenia i wychodzenia z katalogu w celu uruchomienia polecenia?

(Nie szukam rozwiązania specyficznego dla git; to tylko przykład.)

Trevor Burnham
źródło

Odpowiedzi:

202

Jest to często najlepszy sposób:

( cd dir ; git init )

lub

( cd dir && git init )

Jest dość krótki i łatwy do pisania. To uruchamia podpowłokę, więc nie możesz modyfikować z tego środowiska, ale to nie wydaje się być problemem.

Mata
źródło
1
A jeśli musisz ustawić zmienną środowiskową lub dwie, po prostu dodaj ją jako inną komendę na początku.
Hippo
1
@CraigMcQueen: nie bardzo. $?będzie zawierać kod zakończenia ostatniego polecenia uruchomionego w podpowłoce. Jeśli użyjesz &&wariantu (co zwykle powinieneś), otrzymasz kod wyjścia dla pierwszego polecenia, które się nie powiodło (lub 0, jeśli wszystko poszło dobrze).
Mat
Myślę, że nawiasy są opcjonalne
Francis.Beauchamp
10
@ Francis.Beauchamp: jeśli pominiesz pareny, po poleceniu będziesz w podkatalogu, a nie w miejscu, w którym zacząłeś.
Mat
Jak to zrobić w systemie Windows?
Karl Morrison
22

Szukałem sposobu wykonania polecenia git ze ścieżki i wprowadzenia zmian w repozytorium inną ścieżką. Skończyło się na tym pytaniu tutaj.

Ale w przypadku moich konkretnych potrzeb ani zaakceptowana odpowiedź, ani żadna z pozostałych nie pomogła.

Musiałem uruchamiać polecenia git przy użyciu sudo -u USER /usr/bin/git(inny użytkownik go uruchamiający). I jak zapewne wiesz, sudo nie pozwala mi na uruchomienie cdpolecenia, więc nie mogę znajdować się w katalogu repozytorium.

Poszedłem na stronę podręcznika użytkownika git . Wśród opcji widziałem --git-dir=<path>:

--git-dir =

Ustaw ścieżkę do repozytorium. Można to również kontrolować, ustawiając zmienną środowiskową GIT_DIR. Może to być ścieżka bezwzględna lub ścieżka względna do bieżącego katalogu roboczego.

Jeśli więc komuś pomoże, nadal możesz używać git ze ścieżki i wprowadzać zmiany w repozytorium „daleko od ciebie”. Po prostu użyj:

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

lub, aby uruchomić go jako inny użytkownik, wykonaj coś takiego:

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

Również ze strony man git-init :

Jeśli ustawiona jest zmienna środowiskowa $ GIT_DIR, określa ona ścieżkę do użycia zamiast ./.git dla podstawy repozytorium.

Jeśli więc chcesz zainicjować repozytorium w zwykłym folderze .git, musisz określić go wraz z --git-diropcją. na przykład:

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

Po zainicjowaniu repozytorium /path/to/repo/.gitwszystkie dalsze komendy powinny mieć opcję --work-tree=<path>opisaną na stronie man git:

--work-tree =

Ustaw ścieżkę do działającego drzewa. Może to być ścieżka bezwzględna lub ścieżka względem bieżącego katalogu roboczego. Można to również kontrolować, ustawiając zmienną środowiskową GIT_WORK_TREE i zmienną konfiguracyjną core.worktree (więcej szczegółów na ten temat można znaleźć w core.worktree w git-config (1)).

Tak więc właściwym poleceniem do uruchomienia git jako innego użytkownika i zainicjowania nowego repozytorium jest:

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
źródło
Jeśli używasz sudo interaktywnie, a nie za pomocą skryptu, możesz po prostu zrobić sudo -ilub sudo suuzyskać interaktywną powłokę root.
Bugster
Nie mogę sobie wyobrazić, dlaczego ( cd subdir && sudo -u USER /usr/bin/git init )nie miałbym działać.
Scott
Co jeśli nie mam uprawnień dostępu subdir?
dmmd
13

Nie do końca to, o co pytasz (masz prawdziwe odpowiedzi powyżej z podpowłoką), ale spójrz na pushdipopd

Rich Homolka
źródło
Próbowałem z cd && for maven i to nie działało, ale pushd i popd wykonują to doskonale. Dzięki
Radu Toader,
6

Masz kilka opcji. Możesz pogrupować polecenia za pomocą &&lub ;. Lubię to:

cd subdir && git init && cd ..

lub

cd subdir; git init; cd ..

Różnica między nimi polega na tym, że w pierwszym przykładzie, jeśli jedno z poleceń nie powiedzie się, nie wykona pozostałych. W drugim przykładzie wszystkie polecenia będą działać bez względu na wszystko.

Inną opcją byłoby zdefiniowanie funkcji i użycie jej, na przykład:

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

Następnie możesz uruchomić polecenie:

cdinit subdir

I automatycznie znajdzie się git initw tym katalogu i się z niego wyprowadzi.

Możesz również zrobić bardziej złożone rozwiązanie za pomocą funkcji, jeśli masz kilka katalogów i chcesz git initje za pomocą jednego polecenia.

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

Następnie możesz uruchomić to za pomocą:

cdinit subdir1 subdir2 subdir3

I będzie to robić git initw subdir1, subdir2i subdir3.

Wuffers
źródło
Dzięki. Byłem świadomy &&i ;, ale nadzieję na coś bardziej eleganckiego. Brzmi jak napisanie skryptu to moja najlepsza opcja.
Trevor Burnham
Korekta: Ta odpowiedź jest w porządku, ale odpowiedź Mata jest lepsza dla moich konkretnych potrzeb.
Trevor Burnham
Czy uważasz, że twoja cdinitfunkcja może być uogólniona dla dowolnych poleceń? Próbowałem użyć tylko argumentów, ale to nie zadziałało.
Chetan Bhasin
(1) Nowa ;linia jest równoważna, tak że funkcja trzywierszowa jest równoważna cd $1; git init; cd ... (2) Należy zacytować zmienne: "$1", "$@"i "$arg". Lub możesz skrócić for arg in "$@"do for arg.
Scott
5

W przypadku git(przynajmniej w wersji 2.7.0) możesz skorzystać z -Copcji, która powoduje, że git zachowuje się tak, jakby został uruchomiony w danym katalogu. Twoje rozwiązanie może wyglądać następująco:

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

Cytując dokumentację:

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
źródło
2

Możesz pogrupować polecenia za pomocą &&, tj

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

Jeśli nie chcesz żadnej zależności od kodu wyjścia każdej komendy, możesz użyć; zamiast tego, tj .:

cd subdir ; git init ; cd ../
Gafel
źródło
1
Lub ;tak, aby nie zależały od kodu powrotu poprzedniego.
slhck 17.04.11.04
(1)  cd subdir && git init ; cd ..może mieć sens. Jeśli użytkownik chce uruchomić git initpolecenie w subdir, prawdopodobnie nie chce uruchomić polecenia w bieżącym katalogu; tzn. nie chcą go uruchamiać, jeśli (pierwszy) cdzawiedzie. (Chociaż to możliwe, że  cdnie dlatego, że jesteśmy już w subdir, ale to przypadek rogu.) ... (ciąg dalszy)
Scott
(Ciąg dalszy)… Jeśli jednak użytkownik chce traktować blok trzech poleceń jako jednostkę, może chcieć wykonać  cdkopię zapasową w katalogu startowym, nawet jeśli git initpolecenie się nie powiedzie. ( Lub mogą chcieć pozostać w podkatalogu i zdiagnozować błąd polecenia.) (2) Nie musisz uwzględniać /później  ...
Scott
2

Musisz wskoczyć do katalogu docelowego, jeśli polecenie nie ma parametru nazwy pliku lub nazwy katalogu.

Ale możesz napisać skrypt bash, który przyjmuje katalog docelowy i polecenie jako parametry. W tym celu możesz spojrzeć na pushd i popd: http://ss64.com/bash/pushd.html

Napisałbym dla ciebie ten mały skrypt, ale nie mam tu Linux-a :)

wullxz
źródło
Właśnie zobaczyłem odpowiedź Marka Szymańskiego. Możesz po prostu zaimplementować drugi parametr dla polecenia (i zmienić nazwę polecenia) i masz to, czego chcesz.
wullxz 17.04.2011
1

Programy mają różne sposoby obsługi argumentów, więc niektóre będą miały odpowiednik opcji -folder = nazwa . Poza tym wyjątkiem standard, nawet w MS DOS, jest po prostu

$ program podkatalog

Czasem potrzebujesz

katalog programu $ /

Program otworzy folder, będzie pracował z nim w taki sam sposób, jak z plikiem, a po zakończeniu zwróci kontrolę do powłoki, która jest wskazana na oryginalny katalog standardowy. Programy obsługiwane w ten sposób mają problem z tym, że dane wyjściowe błędów (takie jak zrzuty pamięci) trafiają do pliku w bieżącym katalogu powłoki (zamiast podkatalogu ).

Nie można obejść tego problemu, chyba że program ma dostępne przełączniki poleceń określające inne miejsce. Niektórzy programiści biorą licencję artystyczną pomiędzy „program katalogowy został wywołany z ” a „program katalogowy został poproszony o pracę ”.

Vlueboy
źródło