Execute um comando de outro diretório no bash

119

Diga que estou fazendo isso:

cd subdir
git init
cd ../

Existe uma maneira de fazer isso com um único comando, ou talvez dois, em vez de precisar entrar e sair de um diretório para executar um comando lá?

(Não está procurando uma solução específica para o git; isso é apenas um exemplo.)

Trevor Burnham
fonte

Respostas:

202

Geralmente é a melhor maneira:

( cd dir ; git init )

ou

( cd dir && git init )

É bem curto e fácil de digitar. Ele inicia um sub-shell, portanto você não pode modificar seu ambiente a partir disso, mas isso não parece ser um problema aqui.

Esteira
fonte
1
E se você precisar definir uma ou duas variáveis ​​de ambiente, adicione-as como outro comando no início.
Hippo
1
@CraigMcQueen: na verdade não. $?conterá o código de saída do último comando executado no subshell. Se você usar a &&variante (que normalmente deveria), obterá o código de saída do primeiro comando que falhou (ou 0, se tudo der certo).
Mat
Eu acho que os parênteses são opcionais
Francis.Beauchamp
10
@ Francis.Beauchamp: se você omitir as parênteses, estará no subdiretório após o comando, e não no local onde começou.
Mat
Como alguém faz isso no Windows?
Karl Morrison
22

Eu estava procurando uma maneira de executar o comando git a partir de um caminho e fazer alterações no repositório em um caminho diferente. Então, acabei nesta pergunta aqui.

Mas, para minhas necessidades específicas, nem a resposta aceita nem nenhuma das outras ajudaram.

Eu precisava executar comandos git usando sudo -u USER /usr/bin/git(outro usuário executando). E como você deve saber, o sudo não me permite executar o cdcomando, então não posso estar no diretório do repositório.

Então, eu fui para a página de manual do git . E entre as opções, vi o --git-dir=<path>:

--git-dir =

Defina o caminho para o repositório. Isso também pode ser controlado pela configuração da variável de ambiente GIT_DIR. Pode ser um caminho absoluto ou relativo ao diretório de trabalho atual.

Portanto, se isso ajudar alguém, você ainda poderá usar o git de um caminho e fazer alterações em um repositório "longe de você". Apenas use:

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

ou, para executá-lo como outro usuário, faça algo como:

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

Também na página do manual do git-init :

Se a variável de ambiente $ GIT_DIR estiver configurada, ela especificará um caminho a ser usado em vez de ./.git para a base do repositório.

Portanto, se você deseja iniciar o repositório na pasta .git usual, precisará especificá-lo junto com a --git-diropção por exemplo:

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

Após inicializar o repositório /path/to/repo/.git, todos os comandos adicionais devem ter a opção --work-tree=<path>, conforme descrito na página de manual do git:

--work-tree =

Defina o caminho para a árvore de trabalho. Pode ser um caminho absoluto ou relativo ao diretório de trabalho atual. Isso também pode ser controlado pela configuração da variável de ambiente GIT_WORK_TREE e da variável de configuração core.worktree (consulte core.worktree em git-config (1) para uma discussão mais detalhada).

Portanto, o comando certo para executar o git como outro usuário e inicializar um novo repositório é:

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
fonte
Se você estiver usando o sudo interativamente e não através de um script, você pode simplesmente fazer sudo -iou sudo suobter um shell raiz interativo.
Bugster
Não consigo imaginar por ( cd subdir && sudo -u USER /usr/bin/git init )que não funcionaria.
Scott
E se eu não tiver permissão para acessar subdir?
dmmd 24/06
13

Não é exatamente o que você está perguntando (você tem respostas reais acima com o subshell), mas observe pushdepopd

Rich Homolka
fonte
Eu tentei com cd && para maven e não funcionou, mas pushd e popd fazem o trabalho perfeitamente. Obrigado
Radu Toader
6

Você tem poucas opções. Você pode agrupar os comandos com &&ou ;. Como isso:

cd subdir && git init && cd ..

ou

cd subdir; git init; cd ..

A diferença entre eles é que, no primeiro exemplo, se um dos comandos falhar, ele não executará o restante. No segundo exemplo, todos os comandos serão executados, não importa o quê.

Outra opção seria definir uma função e usá-la, por exemplo:

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

Então você pode executar o comando:

cdinit subdir

E ele entrará automaticamente git initnesse diretório e sairá dele.

Você também pode fazer uma solução mais complexa usando uma função se tiver vários diretórios e desejar git initcom um único comando.

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

Você pode executar isso com:

cdinit subdir1 subdir2 subdir3

E ele vai fazer git initno subdir1, subdir2e subdir3.

Wuffers
fonte
Obrigado. Eu estava ciente &&e ;, mas esperava algo mais elegante. Parece que escrever um script é a minha melhor opção.
Trevor Burnham
Correção: Esta resposta é boa, mas a resposta de Mat é melhor para minhas necessidades particulares.
Trevor Burnham
Você acha que sua cdinitfunção pode ser generalizada para comandos arbitrários? Tentei usar apenas os argumentos, mas isso não funcionou.
Chetan Bhasin 23/04
(1) Nova linha é equivalente a ;, de modo que a função de três linhas é equivalente a cd $1; git init; cd ... (2) Você deve citar suas variáveis: "$1", "$@"e "$arg". Ou você pode abreviar for arg in "$@"para for arg.
Scott
5

No caso de git(pelo menos na versão 2.7.0), você pode aproveitar a -Copção que faz o git se comportar como se tivesse sido iniciado no diretório fornecido. Portanto, sua solução pode parecer com:

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

Citando a documentação:

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

Você pode agrupar os comandos com &&, ou seja,

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

Se você não deseja nenhuma dependência do código de saída de cada comando, pode usar; em vez disso, ou seja:

cd subdir ; git init ; cd ../
Gaff
fonte
1
Ou com ;para que eles não dependam do código de retorno do anterior.
slhck
(1)  cd subdir && git init ; cd ..realmente pode fazer mais sentido. Se o usuário deseja executar o git initcomando no subdirdiretório, provavelmente não deseja executar o comando no diretório atual; ou seja, eles não querem executá-lo se o (primeiro) cdfalhar. (Embora seja possível que a  cdfalha falhe porque estamos no subdir, mas esse é um caso de canto.) ... (continua)
Scott
(Continua) ... No entanto, se o usuário quiser tratar o bloco de três comandos como uma unidade, ele poderá  cdfazer backup no diretório inicial, mesmo que o git initcomando falhe. ( Ou eles podem ficar no subdiretório e diagnosticar a falha do comando.) (2) Você não precisa incluir o /depois  ...
Scott
2

Você precisa entrar no diretório de destino se o comando não tiver um parâmetro de nome de arquivo ou diretório.

Mas você pode escrever um script bash que usa o diretório de destino e o comando como parâmetros. Para isso, você pode dar uma olhada em pushd e popd: http://ss64.com/bash/pushd.html

Eu escreveria esse pequeno script para você, mas não tenho uma caixa do Linux aqui :)

wullxz
fonte
Só vi a resposta de Mark Szymanski. Você pode simplesmente implementar um segundo parâmetro para um comando (e renomear o comando) e terá o que deseja.
Wllxz 17/04
1

Os programas têm maneiras diferentes de lidar com argumentos; portanto, alguns terão algum equivalente da opção -folder = name . Além dessa exceção, o padrão, mesmo no MS DOS, é simplesmente

subdiretório $ program

Às vezes você precisa

$ program subdir /

O programa abrirá a pasta, trabalhará com ela da mesma maneira que você trabalha com um arquivo e, quando terminar, retornará o controle ao seu shell, apontado para o diretório padrão original. Os programas tratados dessa maneira têm o problema de que as saídas de erro (como core dumps) vão para um arquivo no diretório atual do seu shell (em vez de subdiretê-lo ).

Não há solução alternativa, a menos que o programa tenha opções de comando disponíveis para especificar um local diferente. Alguns programadores tiram licença artística entre "o programa de diretório foi chamado de " e "o programa de diretório foi instruído a trabalhar ".

Vlueboy
fonte