Como executo um programa com um diretório de trabalho diferente do atual, do shell Linux?

352

Usando um shell Linux , como inicio um programa com um diretório de trabalho diferente do diretório de trabalho atual?

Por exemplo, eu tenho um arquivo binário helloworldque cria o arquivo hello-world.txtno diretório atual .

Este arquivo está dentro do diretório /a.

Atualmente, estou no diretório /b. Quero iniciar meu programa em execução ../a/helloworlde obter o hello-world.txtlugar em um terceiro diretório /c.

Anton Daneyko
fonte
5
Eu descobri da maneira mais difícil que suredefine o diretório de trabalho para o diretório inicial do usuário especificado antes de executar qualquer -ccomando. Isso foi muito útil para mim.
Patrick M

Respostas:

561

Chame o programa assim:

(cd /c; /a/helloworld)

Os parênteses fazem com que um sub-shell seja gerado. Esse sub-shell altera seu diretório de trabalho para /ce executa a helloworldpartir de /a. Após a saída do programa, o sub-shell é finalizado, retornando ao prompt do shell pai, no diretório em que você iniciou.

Tratamento de erros: Para evitar a execução do programa sem ter alterado o diretório, por exemplo, ao escrever incorretamente /c, torne a execução helloworldcondicional:

(cd /c && /a/helloworld)

Reduzindo o uso de memória: Para evitar que o subshell desperdice memória enquanto o hello world é executado, chame helloworldvia exec:

(cd /c && exec /a/helloworld)

[Obrigado a Josh e Juliano por dar dicas sobre como melhorar esta resposta!]

David Schmitt
fonte
11
Alguma maneira de passar argumentos para esse shell? Como em $ 1 e $ 2?
Finiteloop 22/05
2
@segfault: o subshell tem acesso completo ao escopo ao redor.
David Schmitt
Parece que está temporariamente nesse diretório de qualquer maneira, não é?
dhein
11
Você pode passar todos os argumentos, fazendo $ *, $ @ ou "$ @" (se você quiser argumentos para respeitar aspas)
Marcel Valdez Orozco
11
Funcionará se eu adicionar esta linha ao /etc/rc.d/rc.local?
Pratik Patil
95

Semelhante à resposta de David Schmitt , mais a sugestão de Josh, mas não deixa um processo de shell em execução:

(cd /c && exec /a/helloworld)

Dessa forma, é mais parecido com o modo como você geralmente executa comandos no shell. Para ver a diferença prática, você deve executar a ps efpartir de outro shell com cada solução.

Juliano
fonte
Bash builtins manuais exec
Antonios Hadjigeorgalis
25

Uma opção que não requer um subshell e é incorporada ao bash

(pushd SOME_PATH && run_stuff; popd)

Demo:

$ pwd
/home/abhijit
$ pushd /tmp # directory changed
$ pwd
/tmp
$ popd
$ pwd
/home/abhijit
Loren
fonte
11
Uma sugestão semelhante foi feita abaixo por Sahil. Não funciona se o comando falhar. Considere pushd SOME_PATH && run_stuff && popd- se run_stuff falhar, o popd não será executado.
Anton Daneyko
Resposta tardia, isso depende das configurações do arquivo bash. O Bash pode continuar executando comandos mesmo depois de um comando com falha (diferente de usar &&), mas pode ser configurado para não fazer isso usando set -eo arquivo e, em seguida, falharia popd.
Loren
8
Ainda assim, acho que pushd "${SOME_PATH}" && run_stuff; popdé melhor que a resposta atual, uma vez que a semântica pushd / popd foi projetada especificamente para essa situação de entrar em algum diretório e depois voltar ao original.
Marcel Valdez Orozco
Como funciona como definido como alias e preciso passar um parâmetro?
DRB
Eu acho que você precisaria escrever um script de shell para o qual passaria o parâmetro que executaria a série de comandos, pois você não pode passar um parâmetro no meio de um alias. Se você precisar de ajuda para escrever isso, faça uma pergunta separada e faça referência a esta. Depois de ter o script de shell, você pode escrever um alias para chamar seu novo script.
Loren
19
sh -c 'cd /c && ../a/helloworld'
mihi
fonte
11
Utilizado para o jexec do FreeBSD para executar um comando dentro da prisão no diretório de trabalho especificado.
Marián Černý
11

Eu sempre acho que as ferramentas UNIX devem ser escritas como filtros, ler a entrada do stdin e gravar a saída no stdout. Se possível, você pode alterar o binário do helloworld para gravar o conteúdo do arquivo de texto em stdout, em vez de um arquivo específico. Dessa forma, você pode usar o shell para gravar seu arquivo em qualquer lugar.

$ cd ~ / b

$ ~ / a / helloworld> ~ / c / helloworld.txt

Luther Blisset
fonte
6
+1 por estar certo, embora a resposta seja apenas periférica.
25410 David Schmitt
8

Basta alterar o último "&&" para ";" e ele retornará o CD, não importa se o comando falhar ou for bem-sucedido:

cd SOME_PATH && run_some_command ; cd -
johnnybravo
fonte
4

Uma maneira de fazer isso é criar um script de shell wrapper.

O script do shell alteraria o diretório atual para / c, depois executaria / a / helloworld. Depois que o script do shell sai, o diretório atual é revertido para / b.

Aqui está um exemplo de script do shell bash:

#!/bin/bash
cd /c
/a/helloworld
Jin Kim
fonte
2

por que não simplificar

cd SOME_PATH && run_some_command && cd -

o último comando 'cd' o levará de volta ao último diretório pwd. Isso deve funcionar em todos os sistemas * nix.

Sahil
fonte
Está escrita @mezhaka, deveria ter considerado que :)
Sahil
11
Aviso: Se run_some_commandfalhar, cd -não será executado.
starbeamrainbowlabs 12/03
1

Se você sempre deseja que ele vá para / C, use um caminho absoluto ao escrever o arquivo.

Tom Ritter
fonte
0

Se você deseja executar isso dentro do seu programa, eu faria algo como:

#include <unistd.h>
int main()
{
  if(chdir("/c") < 0 )  
  {
     printf("Failed\n");
     return -1 ;
  }

  // rest of your program...

}
Harold
fonte
Ele quer fazer isso em um shell-script, e não em um C. Além disso, seria uma idéia horrível subprocessar o arquivo binário.
-1

do diretório atual forneça o caminho completo para o diretório de scripts para executar o comando

/root/server/user/home/bin/script.sh
Ravi Bhushan
fonte
11
Isso não muda o diretório de trabalho - acho que você está respondendo a uma pergunta diferente daquela que foi solicitada.
Toby Speight
Veio aqui para encontrar uma resposta para a pergunta que você respondeu. Obrigado! lol
kfrncs