Wie führe ich ein Programm mit einem anderen Arbeitsverzeichnis als das aktuelle aus der Linux-Shell aus?

352

Wie starte ich mit einer Linux-Shell ein Programm mit einem anderen Arbeitsverzeichnis als dem aktuellen Arbeitsverzeichnis?

Zum Beispiel habe ich eine Binärdatei helloworld, die die Datei hello-world.txtim aktuellen Verzeichnis erstellt .

Diese Datei befindet sich im Verzeichnis /a.

Derzeit bin ich im Verzeichnis /b. Ich möchte mein Programm starten ../a/helloworldund das hello-world.txtirgendwo in einem dritten Verzeichnis abrufen /c.

Anton Daneyko
quelle
5
Ich habe die schwierige Methode entdeckt, mit der sudas Arbeitsverzeichnis auf das von Ihnen angegebene Ausgangsverzeichnis des Benutzers zurückgesetzt wird, bevor -cBefehle ausgeführt werden. Das war sehr hilfreich für mich.
Patrick M

Antworten:

561

Rufen Sie das Programm folgendermaßen auf:

(cd /c; /a/helloworld)

Die Klammern bewirken, dass eine Unterschale erzeugt wird. Diese Sub-Shell ändert dann ihr Arbeitsverzeichnis in /cund wird dann helloworldvon ausgeführt /a. Nach dem Beenden des Programms wird die Sub-Shell beendet und Sie kehren zu Ihrer Eingabeaufforderung der übergeordneten Shell in dem Verzeichnis zurück, in dem Sie begonnen haben.

Fehlerbehandlung: Um zu vermeiden, dass das Programm ausgeführt wird, ohne das Verzeichnis geändert zu haben, z. B. wenn Sie falsch geschrieben haben /c, machen Sie die Ausführung von helloworldBedingungen abhängig:

(cd /c && /a/helloworld)

Reduzieren der Speichernutzung: Um zu vermeiden, dass die Subshell während der Ausführung von Hello World Speicher verschwendet, rufen Sie helloworldvia exec auf:

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

[Vielen Dank an Josh und Juliano für die Tipps zur Verbesserung dieser Antwort!]

David Schmitt
quelle
1
Gibt es eine Möglichkeit, Argumente an diese Shell zu übergeben? Wie in $ 1 und $ 2?
Finiteloop
2
@segfault: Die Subshell hat vollständigen Zugriff auf den umgebenden Bereich.
David Schmitt
Scheint, als ob es sich sowieso vorübergehend in diesem Verzeichnis befindet, nicht wahr?
Dhein
1
Sie können alle Argumente übergeben, indem Sie $ *, $ @ oder "$ @" ausführen (wenn Sie möchten, dass Argumente doppelte Anführungszeichen berücksichtigen)
Marcel Valdez Orozco
1
Wird es funktionieren, wenn ich diese Zeile zu /etc/rc.d/rc.local hinzufüge?
Pratik Patil
95

Ähnlich wie die Antwort von David Schmitt und der Vorschlag von Josh, lässt jedoch keinen Shell-Prozess laufen:

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

Diese Methode ähnelt eher der Ausführung von Befehlen auf der Shell. Um den praktischen Unterschied zu erkennen, müssen Sie ps efmit jeder Lösung von einer anderen Shell aus laufen .

Juliano
quelle
Bash Manual Builtins Exec
Antonios Hadjigeorgalis
25

Eine Option, für die keine Subshell erforderlich ist und die zum Bash integriert ist

(pushd SOME_PATH && run_stuff; popd)

Demo:

$ pwd
/home/abhijit
$ pushd /tmp # directory changed
$ pwd
/tmp
$ popd
$ pwd
/home/abhijit
Loren
quelle
1
Ein ähnlicher Vorschlag wurde unten von Sahil gemacht. Es funktioniert nicht, wenn der Befehl fehlschlägt. Bedenken Sie pushd SOME_PATH && run_stuff && popd: Wenn run_stuff fehlschlägt, wird popd nicht ausgeführt.
Anton Daneyko
Späte Antwort, das hängt von den Einstellungen der Bash-Datei ab. Bash kann die Ausführung von Befehlen auch nach einem fehlgeschlagenen Befehl fortsetzen (im Gegensatz zur Verwendung von &&). Es kann jedoch so eingestellt werden, dass dies nicht set -ein der Datei verwendet wird, und dies würde dann fehlschlagen popd.
Loren
8
Dennoch denke ich, pushd "${SOME_PATH}" && run_stuff; popdist besser als die aktuelle Antwort, da die Pushd / Popd-Semantik speziell für diese Situation entwickelt wurde, in ein Verzeichnis zu wechseln und dann zum ursprünglichen zurückzukehren.
Marcel Valdez Orozco
Wie funktioniert es als Alias ​​definiert und ich muss einen Parameter übergeben?
DrB
Ich denke, Sie müssten ein Shell-Skript schreiben, an das Sie den Parameter übergeben würden, der die Reihe von Befehlen ausführen würde, da Sie keinen Parameter in der Mitte eines Alias ​​übergeben können. Wenn Sie Hilfe beim Schreiben benötigen, sollten Sie eine separate Frage stellen und auf diese verweisen. Sobald Sie das Shell-Skript haben, können Sie einen Alias ​​schreiben, um Ihr neues Skript aufzurufen.
Loren
19
sh -c 'cd /c && ../a/helloworld'
mihi
quelle
1
Verwendet dies für Jexec von FreeBSD, um einen Befehl im Gefängnis im angegebenen Arbeitsverzeichnis auszuführen.
Marián Černý
11

Ich denke immer, UNIX-Tools sollten als Filter geschrieben werden, Eingaben von stdin lesen und Ausgaben in stdout schreiben. Wenn möglich, können Sie Ihre helloworld-Binärdatei ändern, um den Inhalt der Textdatei in stdout anstatt in eine bestimmte Datei zu schreiben. Auf diese Weise können Sie die Shell verwenden, um Ihre Datei überall zu schreiben.

$ cd ~ / b

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

Luther Blisset
quelle
6
+1 für Recht, obwohl die Antwort nur am Rande eine Antwort ist.
David Schmitt
8

Ändern Sie einfach das letzte "&&" in ";" und es wird zurückgeschickt, egal ob der Befehl fehlschlägt oder erfolgreich ist:

cd SOME_PATH && run_some_command ; cd -
Johnny bravo
quelle
4

Eine Möglichkeit, dies zu tun, besteht darin, ein Wrapper-Shell-Skript zu erstellen.

Das Shell-Skript würde das aktuelle Verzeichnis in / c ändern und dann / a / helloworld ausführen. Nach dem Beenden des Shell-Skripts wird das aktuelle Verzeichnis auf / b zurückgesetzt.

Hier ist ein Beispiel für ein Bash-Shell-Skript:

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

warum nicht einfach halten

cd SOME_PATH && run_some_command && cd -

Der letzte Befehl 'cd' bringt Sie zurück zum letzten pwd-Verzeichnis. Dies sollte auf allen * nix-Systemen funktionieren.

Sahil
quelle
Du schreibst @mezhaka, hätte das berücksichtigen sollen :)
Sahil
1
Warnung: Wenn dies run_some_commandfehlschlägt, cd -wird es nicht ausgeführt.
starbeamrainbowlabs
1

Wenn Sie immer möchten, dass es zu / C geht, verwenden Sie beim Schreiben der Datei einen absoluten Pfad.

Tom Ritter
quelle
0

Wenn Sie dies in Ihrem Programm ausführen möchten, würde ich Folgendes tun:

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

  // rest of your program...

}
Harold
quelle
Er möchte dies in einem Shell-Skript und nicht in einem C tun. Außerdem wäre es eine schreckliche Idee, die Binärdatei zu unterverarbeiten.
-1

Geben Sie aus dem aktuellen Verzeichnis den vollständigen Pfad zum Skriptverzeichnis an, um den Befehl auszuführen

/root/server/user/home/bin/script.sh
Ravi Bhushan
quelle
1
Das ändert das Arbeitsverzeichnis überhaupt nicht - ich denke, Sie beantworten eine andere Frage als die, die gestellt wurde.
Toby Speight
Kam hierher, um eine Antwort auf die Frage zu finden, die Sie beantwortet haben. Vielen Dank! lol
kfrncs