Einen bestimmten Befehl in einem bestimmten Verzeichnis ausführen, ohne ihn zu ändern?

42

Gibt es eine Möglichkeit, einen Befehl in einem anderen Verzeichnis auszuführen, ohne dazu verpflichtet cdzu sein? Ich weiß, dass ich einfach rein cdund cdraus könnte, aber ich bin nur an den Möglichkeiten interessiert, auf die zusätzlichen Schritte zu verzichten :)

Naftuli Kay
quelle
Es ist ziemlich trivial , ein Skript zu machen , das dies tut: echo "#!/bin/bash; cd $1; exec $2" > /usr/local/bin/execindirectory; chmod +x /usr/local/bin/execindirectory. Möglicherweise müssen Sie sich etwas mehr Mühe geben, wenn Sie möchten, dass die Option "Tags" wie -dund so unterstützt wird.
LawrenceC
Wie Benutzerunbekannte in einer Antwort festhalten, werden alle Beispiele, die Sie hier und in Kommentaren angegeben haben, besser von anderen Lösungen angesprochen. Es ist daher unklar, ob es tatsächlich ein Problem gibt, das hier gelöst werden muss. Können Sie sich ein besseres Beispiel ausdenken?
Caleb

Antworten:

55

Ich weiß nicht, ob das zählt, aber Sie können eine Unterschale machen:

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

Das Verzeichnis wird nur für diese Subshell geändert, sodass Sie später keine weiteren Änderungen vornehmen müssen cd -.

Michael Mrozek
quelle
2
Das ist was ich normalerweise tue.
Adam Byrtek
Nett, ich hatte die Unterschalen total vergessen, sehr praktisch in diesem Fall.
Naftuli Kay
4
Um zu vermeiden , mögliches Chaos, sub aus dem Semikolon mit zwei Et - Zeichen: $ (cd /var/log && cp *.log ~/Desktop). Auf diese Weise werden keine weiteren Befehle ausgeführt, wenn das Verzeichnis nicht vorhanden ist.
Naftuli Kay
Beachten Sie für alle so naiven Personen wie mich, dass $ at start nicht Teil des Befehls ist, sondern nur alles, was danach folgt.
Maltronic
14

Einige Programme haben Optionen, mit denen Sie chdir (2) selbst mitteilen können (zB GNU tar 's -C/ --directory).

Außerhalb solcher Programme muss allerdings etwas chdir . Sie könnten ein kompiliertes "Binär" -Programm schreiben und verwenden, anstatt die Shell dazu zu bringen, aber es würde wahrscheinlich keinen großen Nutzen bringen.

In einem Kommentar in einer anderen Antwort gaben Sie ein Beispiel:

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

Da das *.logMuster von der Shell selbst erweitert wird (nicht von cp ), muss etwas in das Verzeichnis chdir , bevor eine Shell Ihren Befehl auswertet.

Wenn Sie nur daran interessiert sind, nicht "zurück" schreiben zu müssen, können Sie eine Subshell verwenden, um den Effekt der CD von Ihrer funktionierenden Shell-Instanz zu isolieren .

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

Sie können dies in eine Shell-Funktion packen. (Ich habe die -dOption aus Ihrer Beispielverwendung entfernt, da dieser Befehl wenig Sinn macht, wenn das Verzeichnis tatsächlich optional ist.)

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
quelle
2
Ich mag diese Lösung, außer dass ich persönlich pushd / popd verwenden würde
NJ
10

Um den Wert der Antworten anderer nicht zu untergraben, aber ich glaube, Sie möchten Folgendes:

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

Beachten Sie die Parens, die cdin einer Unterschale aufgerufen werden sollen.

Alex
quelle
Ich glaube nicht. Soweit ich weiß, möchte er im Ausgangsverzeichnis landen.
Adam Byrtek
Oh, ich habe total vergessen, das in eine Unterschale zu packen. Korrigierte meine Antwort, danke.
alex
4

Hier ist etwas, das Sie zurücklassen sollte, cdwo Sie waren (mit Bash), da es der Zweck der Frage zu sein scheint, dies nicht zu vergessen:

# 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: etwas kürzere Version, dank @ Random832)

Bruno
quelle
1
Sie könnten nur pushd other-dir, anstattpushd .; cd other-dir
Random832
@ Random832, guter Punkt!
Bruno
2

Dein Beispiel:

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

braucht keine Änderung am Verzeichnis, weil

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

würde das gleiche tun. Können Sie Ihrem eigentlichen Problem nicht näher kommen? Weil wir vielleicht auch dafür eine bessere Lösung kennen.

Ein komplizierter Weg, um Ihr Problem zu lösen, der weit von der Eleganz der Michaels-Lösung entfernt ist, ist die Verwendung von find, das einen Schalter '-execdir' hat, der in dem Verzeichnis ausgeführt wird, in dem sich eine Datei befindet. Schlecht in Ihr Beispiel übernommen:

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

Vielleicht ist es nützlich für Ihr echtes Problem. -okdir anstelle von -execdir fordert Sie auf, jeden Aufruf zu bestätigen.

-okdir und -execdir müssen möglicherweise gnu-find installiert haben, was normalerweise unter Linux verwendet wird.

Benutzer unbekannt
quelle
1

Wie wäre es ./your/path/command.sh?

Diktator
quelle
Nein, ich tatsächlich so etwas wie die folgenden gemeint: execindirectory -d /var/log "cp *.log ~/Desktop".
Naftuli Kay
Mir ist durchaus bewusst, dass dies nicht unbedingt erforderlich ist. Mich interessiert übrigens nur, ob es tatsächlich möglich ist.
Naftuli Kay