Executar um comando específico em um determinado diretório sem fazer o cd?

42

Existe uma maneira de executar um comando em um diretório diferente sem precisar fazê cd-lo? Eu sei que eu poderia simplesmente entrar cde cdsair, mas só estou interessado nas possibilidades de renunciar às etapas extras :)

Naftuli Kay
fonte
É bastante trivial para fazer um script que faz isso: echo "#!/bin/bash; cd $1; exec $2" > /usr/local/bin/execindirectory; chmod +x /usr/local/bin/execindirectory. Pode ser necessário um pouco mais de esforço se você quiser realmente oferecer suporte a "tags" de opções, como -doutras coisas.
LawrenceC
Como o usuário desconhecido afirma em uma resposta, todos os exemplos que você deu aqui e nos comentários são mais bem tratados por outras soluções, portanto, não está claro se há realmente um problema que precise ser resolvido aqui. Você pode criar um exemplo melhor?
Caleb

Respostas:

55

Não sei se isso conta, mas você pode fazer um subshell:

$ (cd /var/log && cp -- *.log ~/Desktop)

O diretório é alterado apenas para esse subshell, para evitar o trabalho de precisar cd -depois.

Michael Mrozek
fonte
2
É o que eu costumo fazer.
Adam Byrtek
Bom, eu tinha esquecido completamente as subcascas, muito útil neste caso.
Naftuli Kay
4
Para evitar a possibilidade de caos, sub fora o ponto e vírgula com dois ampersands: $ (cd /var/log && cp *.log ~/Desktop). Dessa forma, se o diretório não existir, nenhum comando adicional será executado.
Naftuli Kay
Nota para qualquer pessoa tão ingênua quanto eu: o $ no início não faz parte do comando, apenas tudo depois dele.
Maltronic 15/04
14

Alguns programas têm opções com as quais você pode dizer a eles próprios para chdir (2) (por exemplo, GNU tar 's -C/ --directory).

Fora de tais programas, porém, algo terá que chdir . Você pode escrever e usar algum tipo de programa "binário" compilado em vez de fazer com que o shell o faça, mas provavelmente não traria muitos benefícios.

Em um comentário em outra resposta, você deu um exemplo:

execindirectory -d /var/log "cp *.log ~/Desktop"

Como o *.logpadrão é expandido pelo próprio shell (não pelo cp ), algo terá que chdir para o diretório antes de um shell avaliar seu comando.

Se você é apenas interessante para evitar ter que “voltar ao cd”, pode usar um subshell para isolar o efeito do cd da sua instância do shell de trabalho.

(cd /path/to/dir && some command)

Você pode empacotar isso em uma função shell. (Abandonei a -dopção do seu exemplo de uso, pois há pouco sentido nesse comando se o diretório for realmente opcional.)

runindir() { (cd "$1" && shift && eval "$@"); }

runindir /var/log 'cp *.log ~/Desktop'  # your example
runindir /var/log cp \*.log \~/Desktop  # eval takes multiple args

runindir /var/log cp \*.log ~/Desktop   # it is okay to expand tilde first
Chris Johnsen
fonte
2
Eu gosto desta solução, a não ser, pessoalmente eu usaria pushd / popd
NJ
10

Não para minar o valor das respostas dadas por outras pessoas, mas acredito que o que você quer é o seguinte:

(cd /path/to && ./executable [ARGS])

Observe as parênteses a serem invocadas cdem um subcasca.

alex
fonte
Acho que não. Pelo que entendi, ele quer acabar no diretório inicial.
Adam Byrtek
Ah, eu esqueci totalmente de colocar isso no sub-shell. Corrigida minha resposta, obrigado.
26411 alex
4

Aqui está uma coisa que deve deixar você cdvoltar onde estava (usando o Bash), já que não esquecer disso parece ser o objetivo da pergunta:

# Save where you are and cd to other dir
pushd /path/to/dir/that/needs/to/be/current/dir

run-your-command

# Get back where you were at the beginning.
popd

(EDIT: versão um pouco mais curta, graças a @ Random832)

Bruno
fonte
1
Você poderia apenas pushd other-dir, em vez depushd .; cd other-dir
Random832
@ Random832, bom ponto!
Bruno
2

Infelizmente, seu exemplo:

execindirectory -d /var/log "cp *.log ~/Desktop"

não precisa de uma alteração no diretório, porque

cp /var/log/*.log ~/Desktop

faria o mesmo. Você não pode se aproximar do seu problema real? Porque também podemos conhecer uma solução melhor para isso.

Uma maneira complicada de resolver seu problema, que está longe da elegância da solução Michaels, é o uso de find, que possui uma opção '-execdir' a ser executada no diretório em que um arquivo é encontrado. Mal adotado no seu exemplo:

find /var/log -maxdepth 1 -type f -name "*.log" -execdir echo cp {} ~/Desktop ";"

Talvez seja útil para o seu problema real. -okdir em vez de -execdir solicitará que você confirme todas as chamadas.

-okdir e -execdir podem precisar do gnu-find para serem instalados, o que normalmente é usado no Linux.

Usuário desconhecido
fonte
1

Que tal ./your/path/command.sh?

ditador
fonte
Não, eu realmente quis dizer algo como o seguinte: execindirectory -d /var/log "cp *.log ~/Desktop".
Naftuli Kay
Estou perfeitamente ciente de que isso não é estritamente necessário, a propósito, só estou interessado se isso pode realmente ser feito.
Naftuli Kay