Thực hiện một lệnh từ một thư mục khác trong bash


119

Nói rằng tôi đang làm điều này:

cd subdir
git init
cd ../

Có cách nào để làm điều này với một lệnh duy nhất, hoặc có lẽ hai, thay vì phải di chuyển vào và ra khỏi một thư mục để chạy một lệnh ở đó?

(Không tìm kiếm một giải pháp cụ thể cho git; đó chỉ là một ví dụ.)

Câu trả lời:


202

Đây thường là cách tốt nhất:

( cd dir ; git init )

hoặc là

( cd dir && git init )

Nó khá ngắn và dễ gõ. Nó bắt đầu một lớp vỏ phụ, vì vậy bạn không thể sửa đổi môi trường của mình từ đó, nhưng dường như đó không phải là vấn đề ở đây.


1
Và nếu bạn cần phải đặt một hoặc hai biến môi trường, chỉ cần thêm nó như một lệnh khác ở đầu.

1
@CraigMcQueen: không thực sự. $?sẽ chứa mã thoát của lệnh cuối cùng chạy trong lớp con. Nếu bạn sử dụng &&biến thể (mà bạn thường nên làm), thì bạn sẽ nhận được mã thoát của lệnh đầu tiên không thành công (hoặc 0 nếu tất cả đều ổn).
Mat

Tôi nghĩ rằng dấu ngoặc đơn là tùy chọn
Francis.Beauchamp

10
@ Francis.Beauchamp: nếu bạn bỏ qua các parens, bạn sẽ ở trong thư mục con sau lệnh thay vì quay lại nơi bạn bắt đầu.
Mat

Làm thế nào để làm điều này trên Windows?
Karl Morrison

22

Tôi đang tìm cách để thực thi lệnh git từ một đường dẫn và thay đổi kho lưu trữ theo một đường dẫn khác. Vì vậy, tôi đã kết thúc câu hỏi này ở đây.

Nhưng đối với các nhu cầu cụ thể của tôi, cả câu trả lời được chấp nhận cũng như bất kỳ câu hỏi nào khác đều có ích.

Tôi cần chạy các lệnh git bằng cách sử dụng sudo -u USER /usr/bin/git(một người dùng khác đang chạy nó). Và như bạn có thể biết, sudo không cho phép tôi chạy cdlệnh, vì vậy tôi không thể ở trong thư mục kho lưu trữ.

Vì vậy, tôi đã đi đến trang người đàn ông của git . Và trong số các tùy chọn, tôi thấy --git-dir=<path>:

--git-dir =

Đặt đường dẫn đến kho lưu trữ. Điều này cũng có thể được kiểm soát bằng cách đặt biến môi trường GIT_DIR. Nó có thể là một đường dẫn tuyệt đối hoặc đường dẫn tương đối đến thư mục làm việc hiện tại.

Vì vậy, nếu nó giúp được ai đó, bạn vẫn có thể sử dụng git từ một đường dẫn và thay đổi kho lưu trữ "cách xa bạn". Chỉ dùng:

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

hoặc, để chạy nó như một người dùng khác, hãy làm một cái gì đó như:

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

Cũng từ trang người đàn ông của git-init :

Nếu biến môi trường $ GIT_DIR được đặt thì nó chỉ định đường dẫn sử dụng thay vì ./.git cho cơ sở của kho lưu trữ.

Vì vậy, nếu bạn muốn khởi tạo kho lưu trữ trong thư mục .git thông thường, bạn sẽ cần chỉ định nó cùng với --git-dirtùy chọn. ví dụ:

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

Sau khi khởi tạo kho lưu trữ trên /path/to/repo/.git, tất cả các lệnh tiếp theo sẽ có tùy chọn --work-tree=<path>, như được mô tả trên trang man của git:

--work-cây =

Đặt đường dẫn đến cây làm việc. Nó có thể là một đường dẫn tuyệt đối hoặc một đường dẫn liên quan đến thư mục làm việc hiện tại. Điều này cũng có thể được kiểm soát bằng cách đặt biến môi trường GIT_WORK_TREE và biến cấu hình core.worktree (xem core.worktree trong git-config (1) để thảo luận chi tiết hơn).

Vì vậy, lệnh đúng để chạy git với tư cách người dùng khác và khởi tạo kho lưu trữ mới là:

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

Nếu bạn đang sử dụng sudo một cách tương tác và không thông qua một tập lệnh, bạn chỉ cần làm sudo -ihoặc sudo suđể có được một vỏ gốc tương tác.
Bugster

Tôi không thể tưởng tượng tại sao ( cd subdir && sudo -u USER /usr/bin/git init )sẽ không làm việc.
Scott

Nếu tôi không được phép truy cập subdirthì sao?
dmmd

13

Không chính xác những gì bạn đang hỏi (bạn có câu trả lời thực sự ở trên với lớp con) nhưng hãy nhìn vào pushdpopd


Tôi đã thử với cd && cho maven và nó không hoạt động, nhưng Pushd và popd thực hiện công việc một cách hoàn hảo. Cảm ơn
Radu Toader

6

Bạn có một vài lựa chọn. Bạn có thể nhóm các lệnh với &&hoặc ;. Như thế này:

cd subdir && git init && cd ..

hoặc là

cd subdir; git init; cd ..

Sự khác biệt giữa chúng là trong ví dụ đầu tiên, nếu một trong các lệnh bị lỗi, nó sẽ không thực thi phần còn lại của chúng. Trong ví dụ thứ hai, tất cả các lệnh sẽ chạy bất kể điều gì.

Một tùy chọn khác là định nghĩa một hàm và sử dụng nó, ví dụ:

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

Sau đó, bạn có thể chạy lệnh:

cdinit subdir

Và nó sẽ tự động git inittrong thư mục đó và di chuyển ra khỏi nó.

Bạn cũng có thể thực hiện một giải pháp phức tạp hơn bằng cách sử dụng hàm nếu bạn có một loạt các thư mục và muốn git initchúng với một lệnh.

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

Sau đó, bạn có thể chạy nó với:

cdinit subdir1 subdir2 subdir3

Và nó sẽ làm git inittrong subdir1, subdir2subdir3.


Cảm ơn. Tôi đã nhận thức được &&;, nhưng hy vọng cho một cái gì đó thanh lịch hơn. Âm thanh như viết một kịch bản là lựa chọn tốt nhất của tôi.
Trevor Burnham

Sửa chữa: Câu trả lời này là tốt, nhưng câu trả lời của Mat tốt hơn cho nhu cầu cụ thể của tôi.
Trevor Burnham

Bạn có nghĩ rằng cdinitchức năng của bạn có thể được tổng quát hóa cho các lệnh tùy ý? Tôi đã cố gắng chỉ sử dụng các đối số, nhưng điều đó không làm việc.
Chetan Bhasin

(1) Dòng mới tương đương với ;, do đó chức năng ba dòng tương đương với cd $1; git init; cd ... (2) Bạn nên trích dẫn các biến của bạn: "$1", "$@""$arg". Hoặc bạn có thể viết tắt for arg in "$@"để for arg.
Scott

5

Trong trường hợp git(ít nhất là trong phiên bản 2.7.0), bạn có thể tận dụng -Ctùy chọn khiến git hoạt động như thể nó được bắt đầu trong thư mục đã cho. Vì vậy, giải pháp của bạn có thể trông giống như:

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

Trích dẫn tài liệu:

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

Bạn có thể nhóm các lệnh với &&, tức là

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

Nếu bạn không muốn bất kỳ sự phụ thuộc vào mã thoát của mỗi lệnh, bạn có thể sử dụng; thay vào đó, tức là:

cd subdir ; git init ; cd ../

1
Hoặc ;để họ không phụ thuộc vào mã trả về của mã trước đó.
slhck

(1)  cd subdir && git init ; cd ..thực sự có thể có ý nghĩa nhất. Nếu người dùng muốn chạy git initlệnh trong subdir, thì có lẽ họ không muốn chạy lệnh trong thư mục hiện tại; tức là, họ không muốn chạy nó nếu (lần đầu tiên) cdthất bại. (Mặc dù nó có thể là  cdthất bại bởi vì chúng tôi đãsubdir, nhưng đó là một trường hợp góc.) ... (Tiếp theo)
Scott

(Tiếp), Tuy nhiên, nếu người dùng muốn coi khối ba lệnh là một đơn vị, họ có thể muốn  cdsao lưu vào thư mục bắt đầu ngay cả khi git initlệnh không thành công. ( Hoặc, họ có thể muốn ở lại thư mục con và chẩn đoán lỗi lệnh.) (2) Bạn không cần đưa vào phần /sau  ...
Scott

2

Bạn phải nhảy vào thư mục đích nếu lệnh không có tham số tên tệp hoặc tên thư mục.

Nhưng bạn có thể viết một tập lệnh bash lấy thư mục đích và lệnh làm tham số. Đối với điều này, bạn có thể xem qua Pushd và popd: http://ss64.com/bash/pushd.html

Tôi sẽ viết kịch bản nhỏ đó cho bạn, nhưng tôi không có hộp Linux ở đây :)


Chỉ cần nhìn thấy câu trả lời từ Mark Szymanski. Bạn chỉ có thể thực hiện một tham số thứ hai cho một lệnh (và đổi tên lệnh) và bạn có những gì bạn muốn.
wullxz

1

Các chương trình có các cách xử lý đối số khác nhau, vì vậy một số ít sẽ có một số tùy chọn tương đương -folder = name . Ngoài ngoại lệ đó, tiêu chuẩn, ngay cả trên MS DOS, chỉ đơn giản là

$ Chương trình subdir

Đôi khi bạn cần

$ chương trình con /

Chương trình sẽ mở thư mục, hoạt động với nó giống như cách bạn làm việc với một tệp và sau khi hoàn tất, trả lại quyền điều khiển cho trình bao của bạn, được trỏ vào thư mục chuẩn ban đầu của bạn. Chương trình xử lý theo cách này DO có vấn đề mà kết quả đầu ra lỗi (như lõi bãi) đi đến một tập tin trong thư mục hiện hành của shell của bạn (chứ không phải subdir .)

Không có cách giải quyết trừ khi chương trình có sẵn các công tắc lệnh để chỉ định một địa điểm khác. Một số lập trình viên có giấy phép nghệ thuật giữa "chương trình thư mục được gọi từ " và "chương trình thư mục được yêu cầu làm việc ."

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.