Jalankan perintah dari direktori lain di bash

119

Katakan bahwa saya melakukan ini:

cd subdir
git init
cd ../

Apakah ada cara untuk melakukan ini dengan satu perintah, atau mungkin dua, daripada harus masuk dan keluar dari direktori untuk menjalankan perintah di sana?

(Tidak mencari solusi spesifik git; itu hanya contoh.)

Trevor Burnham
sumber

Jawaban:

202

Ini seringkali merupakan cara terbaik:

( cd dir ; git init )

atau

( cd dir && git init )

Cukup pendek dan mudah diketik. Itu memang memulai sub-shell, jadi Anda tidak dapat mengubah lingkungan Anda dari itu, tetapi itu tampaknya tidak menjadi masalah di sini.

Tikar
sumber
1
Dan jika Anda perlu mengatur satu atau dua variabel lingkungan, tambahkan saja itu sebagai perintah lain di awal.
Hippo
1
@CraigMcQueen: tidak juga. $?akan berisi kode keluar dari perintah terakhir yang dijalankan di subkulit. Jika Anda menggunakan &&varian (yang biasanya Anda harus), maka Anda akan mendapatkan kode keluar dari perintah pertama yang gagal (atau 0 jika semua berjalan ok).
Mat
Saya pikir kurung adalah opsional
Francis.Beauchamp
10
@ Francis.Beauchamp: jika Anda menghilangkan parens, Anda akan berada di subdir setelah perintah daripada kembali ke tempat Anda mulai.
Mat
Bagaimana cara melakukan ini pada Windows?
Karl Morrison
22

Saya mencari cara untuk mengeksekusi perintah git dari sebuah path, dan membuat perubahan pada repositori di path yang berbeda. Jadi saya berakhir dengan pertanyaan ini di sini.

Tetapi untuk kebutuhan spesifik saya, baik jawaban yang diterima maupun yang lain tidak membantu.

Saya perlu menjalankan perintah git menggunakan sudo -u USER /usr/bin/git(pengguna lain yang menjalankannya). Dan seperti yang Anda ketahui, sudo tidak mengizinkan saya menjalankan cdperintah, jadi saya tidak bisa berada di direktori repositori.

Jadi, saya pergi ke halaman manual git . Dan di antara beberapa opsi, saya melihat --git-dir=<path>:

--git-dir =

Setel path ke repositori. Ini juga dapat dikontrol dengan mengatur variabel lingkungan GIT_DIR. Ini bisa menjadi jalur absolut atau jalur relatif ke direktori kerja saat ini.

Jadi, jika itu membantu seseorang, Anda masih bisa menggunakan git dari path dan membuat perubahan pada repositori "jauh dari Anda". Cukup gunakan:

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

atau, untuk menjalankannya sebagai pengguna lain, lakukan sesuatu seperti:

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

Juga dari halaman manual git-init :

Jika variabel lingkungan $ GIT_DIR disetel, maka ia menentukan lintasan untuk digunakan sebagai ganti ./.git untuk basis repositori.

Jadi, jika Anda ingin init repositori di bawah folder .git yang biasa, Anda harus menentukannya bersama dengan --git-diropsi. misalnya:

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

Setelah menginisialisasi repositori /path/to/repo/.git, semua perintah lebih lanjut harus memiliki opsi --work-tree=<path>, seperti yang dijelaskan pada halaman manual git:

--work-tree =

Atur jalur ke pohon yang berfungsi. Ini bisa menjadi jalur absolut atau jalur relatif ke direktori kerja saat ini. Ini juga dapat dikontrol dengan mengatur variabel lingkungan GIT_WORK_TREE dan variabel konfigurasi core.worktree (lihat core.worktree di git-config (1) untuk diskusi yang lebih rinci).

Jadi, perintah yang tepat untuk menjalankan git sebagai pengguna lain, dan menginisialisasi repositori baru adalah:

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
sumber
Jika Anda menggunakan sudo secara interaktif dan tidak melalui skrip, Anda cukup melakukan sudo -iatau sudo suuntuk mendapatkan shell root interaktif.
Bugster
Saya tidak bisa membayangkan mengapa ( cd subdir && sudo -u USER /usr/bin/git init )tidak berhasil.
Scott
Bagaimana jika saya tidak memiliki izin untuk mengakses subdir?
dmmd
13

Tidak persis apa yang Anda minta (Anda memiliki jawaban nyata di atas dengan subkulit) tetapi lihat pushddanpopd

Homolka yang kaya
sumber
Saya mencoba dengan cd && untuk maven dan tidak berhasil, tetapi pushd dan popd melakukan pekerjaan dengan sempurna. Terima kasih
Radu Toader
6

Anda punya beberapa pilihan. Anda dapat mengelompokkan perintah dengan &&atau ;. Seperti ini:

cd subdir && git init && cd ..

atau

cd subdir; git init; cd ..

Perbedaannya adalah dalam contoh pertama, jika salah satu perintah gagal, ia tidak akan menjalankan sisanya. Dalam contoh kedua, semua perintah akan berjalan apa pun yang terjadi.

Opsi lain adalah mendefinisikan fungsi dan menggunakannya, misalnya:

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

Kemudian Anda dapat menjalankan perintah:

cdinit subdir

Dan itu akan secara otomatis git initdi direktori itu dan keluar.

Anda juga bisa melakukan solusi yang lebih kompleks menggunakan fungsi jika Anda memiliki banyak direktori dan ingin git initmereka dengan satu perintah.

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

Anda kemudian dapat menjalankan ini dengan:

cdinit subdir1 subdir2 subdir3

Dan akan melakukan git initdi subdir1, subdir2, dan subdir3.

Wuffers
sumber
Terima kasih. Saya sadar &&dan ;, tetapi berharap untuk sesuatu yang lebih elegan. Kedengarannya seperti menulis naskah adalah pilihan terbaik saya.
Trevor Burnham
Koreksi: Jawaban ini baik-baik saja, tetapi jawaban Mat lebih baik untuk kebutuhan khusus saya.
Trevor Burnham
Apakah Anda pikir cdinitfungsi Anda dapat digeneralisasi untuk perintah yang sewenang-wenang? Saya mencoba menggunakan argumen saja, tetapi itu tidak berhasil.
Chetan Bhasin
(1) Newline setara dengan ;, sehingga fungsi tiga baris setara dengan cd $1; git init; cd ... (2) Anda harus mengutip variabel Anda: "$1", "$@"dan "$arg". Atau Anda dapat menyingkat for arg in "$@"ke for arg.
Scott
5

Dalam hal git(setidaknya dalam versi 2.7.0), Anda dapat memanfaatkan -Copsi yang membuat git berperilaku seolah-olah itu dimulai di direktori yang diberikan. Jadi solusi Anda mungkin terlihat seperti:

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

Mengutip dokumentasi:

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
sumber
2

Anda dapat mengelompokkan perintah dengan &&, yaitu

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

Jika Anda tidak ingin ada ketergantungan pada kode keluar dari setiap perintah, Anda dapat menggunakan; sebaliknya, yaitu:

cd subdir ; git init ; cd ../
Taji
sumber
1
Atau dengan ;begitu mereka tidak bergantung pada kode pengembalian yang sebelumnya.
slhck
(1)  cd subdir && git init ; cd ..sebenarnya mungkin paling masuk akal. Jika pengguna ingin menjalankan git initperintah di subdir, maka mereka mungkin tidak ingin menjalankan perintah di direktori saat ini; yaitu, mereka tidak ingin menjalankannya jika (pertama) cdgagal. (Meskipun ada kemungkinan bahwa  cdgagal karena kita sudah di subdir, tapi itu kasus sudut.) ... (Lanjutan)
Scott
(Lanjutkan) ... Namun, jika pengguna ingin memperlakukan blok tiga perintah sebagai satu unit, mereka mungkin ingin  cdmembuat cadangan ke direktori awal bahkan jika git initperintah gagal. ( Atau, mereka mungkin ingin tinggal di subdirektori dan mendiagnosa kegagalan perintah.) (2) Anda tidak perlu menyertakan /setelah  ...
Scott
2

Anda harus masuk ke direktori target Anda jika perintah tidak memiliki parameter nama file atau nama direktori.

Tetapi Anda dapat menulis skrip bash yang mengambil direktori target dan perintah sebagai parameter. Untuk ini, Anda bisa melihat pushd dan popd: http://ss64.com/bash/pushd.html

Saya akan menulis skrip kecil itu untuk Anda, tetapi saya tidak memiliki kotak Linux di sini :)

wullxz
sumber
Baru saja melihat jawaban dari Mark Szymanski. Anda bisa menerapkan parameter kedua untuk sebuah perintah (dan mengganti nama perintah) dan Anda memiliki apa yang Anda inginkan.
wullxz
1

Program memiliki cara penanganan argumen yang berbeda, sehingga beberapa akan memiliki opsi -folder = nama yang setara . Di luar pengecualian itu, standarnya, bahkan pada MS DOS, adalah sederhana

$ subdir program

Terkadang Anda membutuhkannya

$ subdir program /

Program akan membuka folder, bekerja dengannya seperti halnya Anda bekerja dengan file, dan setelah selesai, kembalikan kontrol ke shell Anda, yang diarahkan ke direktori standar asli Anda. Program-program yang ditangani dengan cara ini DO memiliki masalah bahwa output kesalahan (seperti dump inti) pergi ke file di direktori shell Anda saat ini (bukan subdir .)

Tidak ada solusi kecuali program memiliki sakelar perintah yang tersedia untuk menentukan tempat yang berbeda. Beberapa programmer mengambil lisensi artistik antara "program direktori dipanggil dari " dan "program direktori disuruh bekerja ."

Vlueboy
sumber