Czy wykonać konkretną komendę w danym katalogu bez cd'owania?

42

Czy istnieje sposób na wykonanie polecenia w innym katalogu bez potrzeby cd? Wiem, że mogłem po prostu wchodzić cdi cdwychodzić, ale interesują mnie możliwości rezygnacji z dodatkowych kroków :)

Naftuli Kay
źródło
To raczej trywialny zrobić skrypt, który wykonuje to: echo "#!/bin/bash; cd $1; exec $2" > /usr/local/bin/execindirectory; chmod +x /usr/local/bin/execindirectory. Może wymagać trochę więcej wysiłku, jeśli chcesz, aby rzeczywiście obsługiwał „tagi” opcji, takie jak -di inne.
LawrenceC
Jak podaje nieznany użytkownik w odpowiedzi, wszystkie podane tutaj przykłady i komentarze lepiej rozwiązują inne rozwiązania, więc nie jest jasne, czy rzeczywiście istnieje problem, który należy rozwiązać tutaj. Czy możesz wymyślić lepszy przykład?
Caleb

Odpowiedzi:

55

Nie wiem, czy to się liczy, ale możesz utworzyć podpowłokę:

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

Katalog jest zmieniany tylko dla tej podpowłoki, dzięki czemu unikasz pracy cd -późniejszej.

Michał Mrożek
źródło
2
Tak zwykle robię.
Adam Byrtek
Fajnie, zupełnie zapomniałem o podpowłokach, w tym przypadku bardzo przydatnych.
Naftuli Kay
4
Aby uniknąć potencjalnego chaosu, SUB OUT średnikiem z dwoma ampersandów: $ (cd /var/log && cp *.log ~/Desktop). W ten sposób, jeśli katalog nie istnieje, nie są wykonywane dalsze polecenia.
Naftuli Kay,
Uwaga dla każdego, kto jest tak naiwny jak ja: $ na początku nie jest częścią polecenia, tylko wszystko po nim.
Maltronic
14

Niektóre programy mają opcje, za pomocą których możesz im powiedzieć, aby sami chdir (2) (np. GNU tar 's -C/ --directory).

Jednak poza takimi programami coś będzie musiało zmienić . Mógłbyś napisać i użyć jakiegoś skompilowanego programu „binarnego” zamiast zmuszać powłokę do zrobienia tego, ale prawdopodobnie nie przyniosłoby to wiele korzyści.

W komentarzu w innej odpowiedzi podałeś przykład:

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

Ponieważ *.logwzór jest rozszerzony przez samą (nie skorupkach cp ), coś będą musieli chdir do katalogu przed posiadające powłokę ocenić swoje polecenie.

Jeśli po prostu interesuje Cię unikanie konieczności „cofania dysku CD”, możesz użyć podpowłoki w celu odizolowania efektu płyty CD od działającej instancji powłoki.

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

Możesz spakować to w funkcji powłoki. (Usunąłem -dopcję z twojego przykładowego użycia, ponieważ nie ma sensu tego polecenia, jeśli katalog jest opcjonalny).

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
źródło
2
Podoba mi się to rozwiązanie, z wyjątkiem tego, że osobiście użyłbym pushd / popd
NJ
10

Nie podważam wartości odpowiedzi udzielanych przez innych ludzi, ale wierzę, że chcesz tego:

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

Zwróć uwagę na pareny do wywołania cdw podpowłoce.

alex
źródło
Nie wydaje mi się Jak rozumiem, chce skończyć w katalogu początkowym.
Adam Byrtek
Och, całkowicie zapomniałem zawinąć to w podpowłokę. Poprawiłem moją odpowiedź, dziękuję.
alex
4

Oto coś, co powinno pozwolić ci cdwrócić tam, gdzie byłeś (używając Bash), ponieważ nie zapomnienie o tym wydaje się być celem pytania:

# 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

(EDYCJA: nieco krótsza wersja, dzięki @ Random832)

Bruno
źródło
1
możesz po prostu pushd other-dir, zamiastpushd .; cd other-dir
Random832
@ Random832, dobry punkt!
Bruno
2

Niestety twój przykład:

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

nie potrzebuje zmiany w katalogu, ponieważ

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

zrobiłby to samo. Czy nie możesz zbliżyć się do swojego prawdziwego problemu? Ponieważ możemy również znać lepsze rozwiązanie tego problemu.

Skomplikowanym sposobem rozwiązania problemu, który jest daleki od elegancji rozwiązania Michaels, jest użycie funkcji find, która ma przełącznik „-execdir” do wykonania w katalogu, w którym znajduje się plik. Źle przystosowane do twojego przykładu:

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

Może jest to przydatne dla twojego prawdziwego problemu. -okdir zamiast -execdir poprosi o potwierdzenie każdego wywołania.

-okdir i -execdir mogą wymagać zainstalowania gnu-find, zwykle używanego w Linuksie.

nieznany użytkownik
źródło
1

Jak o ./your/path/command.sh?

bdictator
źródło
Nie, tak naprawdę na myśli coś jak następuje: execindirectory -d /var/log "cp *.log ~/Desktop".
Naftuli Kay
Doskonale zdaję sobie sprawę, że nie jest to absolutnie konieczne, interesuje mnie tylko, czy da się to zrobić.
Naftuli Kay