Виконайте команду з іншого каталогу в bash


119

Скажіть, що я роблю це:

cd subdir
git init
cd ../

Чи є спосіб зробити це за допомогою однієї команди чи, можливо, двох, а не для переміщення в каталог та виходу з нього для того, щоб запустити команду там?

(Не шукаю конкретного рішення для git; це лише приклад.)

Відповіді:


202

Це часто найкращий спосіб:

( cd dir ; git init )

або

( cd dir && git init )

Він досить короткий і простий в наборі. Він запускає підкожу, тому ви не можете змінювати своє оточення з цього боку, але це, здається, тут не є проблемою.


1
І якщо вам потрібно встановити змінну середовища або дві, просто додайте це як іншу команду на початку.
Бегемот

1
@CraigMcQueen: не дуже. $?буде містити код виходу останньої команди, що запускалася в підпакеті. Якщо ви використовуєте &&варіант (який зазвичай слід), ви отримаєте код виходу першої команди, яка не вдалася (або 0, якщо все пішло нормально).
Мат

Я думаю, що круглі дужки необов’язкові
Френсіс Бёшан

10
@ Francis.Beauchamp: якщо ви опустите паролі, ви опинитесь у піддіректорі після команди, а не туди, де ви почали.
Мат

Як це зробити в Windows?
Карл Моррісон

22

Я шукав спосіб виконати команду git з шляху та внести зміни до сховища іншим шляхом. Тому я закінчився цим питанням тут.

Але для моїх конкретних потреб не допомогла ні прийнята відповідь, ні будь-яка інша.

Мені потрібно було запускати команди git за допомогою sudo -u USER /usr/bin/git(інший користувач, який його виконує). І як ви знаєте, sudo не дозволяє мені запустити cdкоманду, тому я не можу бути в каталозі репозиторію.

Отже, я перейшов на сторінку git's man . І серед варіантів я побачив --git-dir=<path>:

--git-dir =

Встановіть шлях до сховища. Це також можна контролювати, встановивши змінну середовища GIT_DIR. Це може бути абсолютний шлях або відносний шлях до поточного робочого каталогу.

Отже, якщо це допоможе комусь, ви все одно можете використовувати git із шляху та вносити зміни до сховища "далеко від вас". Просто використовуйте:

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

або, щоб запустити його як іншого користувача, зробіть щось на кшталт:

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

Також зі сторінки чоловіка git-init :

Якщо встановлена ​​змінна середовища $ GIT_DIR, то вона визначає шлях для використання замість ./.git для бази сховища.

Отже, якщо ви хочете запустити сховище у звичайну папку .git, вам потрібно буде вказати його разом із --git-dirпараметром. наприклад:

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

Після ініціалізації репозиторія у /path/to/repo/.gitвсіх подальших командах має бути параметр --work-tree=<path>, як описано на сторінці користувача git:

- робота-дерево =

Встановіть шлях до робочого дерева. Це може бути абсолютний шлях або шлях відносно поточного робочого каталогу. Це також можна керувати, встановивши змінну середовища GIT_WORK_TREE та змінну конфігурації core.worktree (для більш детальної дискусії див. Core.worktree в git-config (1)).

Отже, правильною командою для запуску git як іншого користувача та ініціалізації нового сховища є:

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

Якщо ви використовуєте sudo інтерактивно, а не через скрипт, ви можете просто зробити sudo -iабо sudo suотримати інтерактивну кореневу оболонку.
Багстер

Я не уявляю, чому ( cd subdir && sudo -u USER /usr/bin/git init )б не вийшло.
Скотт

Що робити, якщо я не маю дозволу на доступ subdir?
dmmd

13

Не зовсім те , що ви просите ( у вас є реальні відповіді вище з субоболочкой) , але дивитися на pushdіpopd


Я спробував з CD && для Maven, і це не спрацювало, але pushd і popd справляють цю роботу ідеально. Спасибі
Radu Toader

6

У вас є кілька варіантів. Ви можете або згрупувати команди з &&або ;. Подобається це:

cd subdir && git init && cd ..

або

cd subdir; git init; cd ..

Різниця між ними полягає в тому, що в першому прикладі, якщо одна з команд виходить з ладу, вона не виконає решту з них. У другому прикладі всі команди будуть виконуватися незалежно від того.

Іншим варіантом було б визначити функцію та використовувати її, наприклад:

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

Потім ви можете запустити команду:

cdinit subdir

І він автоматично перейде git initв цей каталог і вийде з нього.

Ви також можете зробити більш складне рішення, використовуючи функцію, якщо у вас є купа каталогів і хочете в git initних за допомогою однієї команди.

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

Потім ви можете запустити це за допомогою:

cdinit subdir1 subdir2 subdir3

І він буде робити git initв subdir1, subdir2і subdir3.


Дякую. Я був в курсі &&і ;, але сподівався на що - то більш елегантне. Здається, що написання сценарію - це мій найкращий варіант.
Тревор Бернхем

Виправлення: Ця відповідь чудова, але відповідь Мата краще для моїх потреб.
Тревор Бернхем

Як ви вважаєте, чи можна вашу cdinitфункцію узагальнити для довільних команд? Я спробував використовувати лише аргументи, але це не вийшло.
Четан Бхасін

(1) Новий рядок еквівалентний ;, так що трирядкова функція еквівалентна cd $1; git init; cd ... (2) Ви повинні процитувати змінні: "$1", "$@"і "$arg". Або можна скоротити for arg in "$@"до for arg.
Скотт

5

У випадку git(принаймні, у версії 2.7.0) ви можете використовувати -Cпараметр, який змушує git вести себе так, ніби він був запущений у заданому каталозі. Тож ваше рішення може виглядати так:

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

Цитування документації:

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

Ви можете згрупувати команди за допомогою &&, тобто

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

Якщо ви не хочете ніякої залежності від коду виходу кожної команди, ви можете використовувати; натомість, тобто:

cd subdir ; git init ; cd ../

1
Або з ;тим, щоб вони не залежали від коду повернення попереднього.
slhck

(1)  cd subdir && git init ; cd ..насправді може мати найбільший сенс. Якщо користувач хоче запустити git initкоманду в subdir, тоді він, ймовірно, не хоче запускати команду в поточному каталозі; тобто вони не хочуть запускати його, якщо (перший) cdне працює. (Хоча можливо, що  cdне вдається, тому що ми вже перебуваємо в subdir, але це кутовий випадок.)… (Продовжував)
Скотт,

(Продовження)… Однак, якщо користувач хоче ставитись до блоку трьох команд як до одиниці, він може захотіти створити  cdрезервну копію до початкового каталогу, навіть якщо git initкоманда не працює. ( Або вони можуть захотіти залишитися у підкаталозі та діагностувати збій команди.) (2) Вам не потрібно включати /після  ...
Скотт

2

Якщо команда не має параметра файлу імені файлу чи імені каталогу, ви повинні перейти у вашу цільову директорію.

Але ви можете написати скрипт bash, який приймає цільовий каталог та команду як параметри. Для цього ви можете подивитися на pushd і popd: http://ss64.com/bash/pushd.html

Я написав би для вас цей маленький сценарій, але тут я не маю Linux-скриньки :)


Щойно побачив відповідь від Марка Шиманського. Ви можете просто реалізувати другий параметр для команди (і перейменувати команду), і у вас є те, що ви хочете.
wullxz

1

Програми мають різні способи обробки аргументів, тому деякі з них матимуть еквівалент параметра -folder = name . Крім цього винятку, стандарт навіть у MS DOS - просто

$ program subdir

Іноді вам потрібно

$ program subdir /

Програма відкриє папку, працюватиме з нею так само, як ви працюєте з файлом, і як тільки закінчите, поверніть контроль у свою оболонку, яка вказана на ваш початковий стандартний каталог. Програми, оброблені таким чином, DO мають проблему, що результати помилок (як основні дампи) переходять у файл у поточному каталозі вашої оболонки (а не в subdir .)

Немає вирішення, якщо в програмі не буде доступних командних перемикачів, щоб вказати інше місце. Деякі програмісти приймають мистецьку ліцензію між тим, щоб "каталог програми був викликаний з " та "Директорія програми була наказана працювати ".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.