Comment exécuter un programme avec un répertoire de travail différent du courant, du shell Linux?

352

En utilisant un shell Linux , comment démarrer un programme avec un répertoire de travail différent du répertoire de travail actuel?

Par exemple, j'ai un fichier binaire helloworldqui crée le fichier hello-world.txtdans le répertoire courant .

Ce fichier se trouve dans le répertoire /a.

Actuellement, je suis dans l'annuaire /b. Je veux démarrer mon programme en cours d'exécution ../a/helloworldet obtenir le hello-world.txtquelque part dans un troisième répertoire /c.

Anton Daneyko
la source
5
J'ai découvert la manière dure qui suréinitialise le répertoire de travail dans le répertoire personnel de l'utilisateur que vous spécifiez avant d'exécuter des -ccommandes. Cela m'a été très utile.
Patrick M

Réponses:

561

Appelez le programme comme ceci:

(cd /c; /a/helloworld)

Les parenthèses provoquent la génération d'un sous-shell. Ce sous-shell change alors son répertoire de travail en /c, puis s'exécute à helloworldpartir de /a. Une fois le programme terminé, le sous-shell se termine, vous renvoyant à l'invite du shell parent, dans le répertoire à partir duquel vous avez démarré.

Gestion des erreurs: pour éviter d'exécuter le programme sans avoir changé le répertoire, par exemple en cas d'orthographe /c, rendre l'exécution de helloworldconditionnelle:

(cd /c && /a/helloworld)

Réduction de l'utilisation de la mémoire: pour éviter d'avoir la mémoire perdue du sous-shell pendant l'exécution de hello world, appelez helloworldvia exec:

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

[Merci à Josh et Juliano d' avoir donné des conseils pour améliorer cette réponse!]

David Schmitt
la source
1
Est-il possible de passer des arguments à ce shell? Comme dans 1 $ et 2 $?
finiteloop
2
@segfault: le sous-shell a un accès complet à la portée environnante.
David Schmitt
On dirait qu'il est temporairement dans ce répertoire de toute façon, n'est-ce pas?
dhein
1
Vous pouvez passer tous les arguments en faisant $ *, $ @ ou "$ @" (si vous voulez que les arguments respectent les guillemets doubles)
Marcel Valdez Orozco
1
Est-ce que cela fonctionnera si j'ajoute cette ligne à /etc/rc.d/rc.local?
Pratik Patil
95

Semblable à la réponse de David Schmitt , plus la suggestion de Josh, mais ne laisse pas de processus shell en cours:

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

Cette façon est plus similaire à la façon dont vous exécutez habituellement les commandes sur le shell. Pour voir la différence pratique, vous devez exécuter à ps efpartir d'un autre shell avec chaque solution.

Juliano
la source
Bash manual builtins exec
Antonios Hadjigeorgalis
25

Une option qui ne nécessite pas de sous-shell et est intégrée à bash

(pushd SOME_PATH && run_stuff; popd)

Démo:

$ pwd
/home/abhijit
$ pushd /tmp # directory changed
$ pwd
/tmp
$ popd
$ pwd
/home/abhijit
Loren
la source
1
Sahil a fait une suggestion similaire ci-dessous. Cela ne fonctionne pas si la commande échoue. Considérez pushd SOME_PATH && run_stuff && popd- si run_stuff échoue, alors popd ne va pas être exécuté.
Anton Daneyko
Réponse tardive, cela dépend des paramètres du fichier bash. Bash peut continuer à exécuter des commandes même après une commande ayant échoué (contrairement à l'utilisation de &&), mais il peut être configuré pour ne pas le faire en utilisant set -edans le fichier et il échouera popd.
Loren
8
Pourtant, je pense que pushd "${SOME_PATH}" && run_stuff; popdc'est mieux que la réponse actuelle, car la sémantique pushd / popd a été spécialement conçue pour cette situation d'aller dans un répertoire et de revenir ensuite à l'original.
Marcel Valdez Orozco
Comment ça marche comme défini comme alias et je dois passer un param?
DrB
Je pense que vous auriez besoin d'écrire un script shell auquel vous passeriez le paramètre qui exécuterait la série de commandes car vous ne pouvez pas passer un paramètre au milieu d'un alias. Si vous avez besoin d'aide pour rédiger cela, vous devez poser une question distincte et y faire référence. Une fois que vous avez le script shell, vous pouvez écrire un alias pour appeler votre nouveau script.
Loren
19
sh -c 'cd /c && ../a/helloworld'
mihi
la source
1
Utilisé pour le jexec de FreeBSD pour exécuter une commande à l'intérieur de la prison dans le répertoire de travail spécifié.
Marián Černý
11

Je pense toujours que les outils UNIX doivent être écrits sous forme de filtres, lire l'entrée depuis stdin et écrire la sortie vers stdout. Si possible, vous pouvez modifier votre binaire helloworld pour écrire le contenu du fichier texte sur stdout plutôt que sur un fichier spécifique. De cette façon, vous pouvez utiliser le shell pour écrire votre fichier n'importe où.

$ cd ~ / b

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

Luther Blisset
la source
6
+1 pour avoir raison, bien que la réponse ne soit qu'une réponse périphérique.
David Schmitt
8

Changez simplement le dernier "&&" en ";" et il reviendra en arrière, peu importe si la commande échoue ou réussit:

cd SOME_PATH && run_some_command ; cd -
johnnybravo
la source
4

Une façon de le faire est de créer un script shell wrapper.

Le script shell changerait le répertoire courant en / c, puis exécuterait / a / helloworld. Une fois le script shell terminé, le répertoire en cours revient à / b.

Voici un exemple de script shell bash:

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

pourquoi ne pas rester simple

cd SOME_PATH && run_some_command && cd -

la dernière commande 'cd' vous ramènera au dernier répertoire pwd. Cela devrait fonctionner sur tous les systèmes * nix.

Sahil
la source
Vous écrivez @mezhaka, aurait dû considérer cela :)
Sahil
1
Avertissement: en cas d' run_some_commandéchec, cd -ne sera pas exécuté.
starbeamrainbowlabs
1

Si vous souhaitez toujours qu'il aille dans / C, utilisez un chemin absolu lorsque vous écrivez le fichier.

Tom Ritter
la source
0

Si vous souhaitez effectuer cela dans votre programme, je ferais quelque chose comme:

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

  // rest of your program...

}
Harold
la source
Il veut le faire dans un shell-script, et non dans un C. Aussi, ce serait une horrible idée de sous-traiter le fichier binaire.
-1

à partir du répertoire en cours fournir le chemin d'accès complet au répertoire de script pour exécuter la commande

/root/server/user/home/bin/script.sh
Ravi Bhushan
la source
1
Cela ne change pas du tout le répertoire de travail - je pense que vous répondez à une question différente de celle qui a été posée.
Toby Speight
Je suis venu ici pour trouver une réponse à la question à laquelle vous avez répondu. Merci! lol
kfrncs