Выполнить определенную команду в данном каталоге, не обращаясь к нему?

42

Есть ли способ выполнить команду в другом каталоге без необходимости cd? Я знаю, что мог бы просто входить cdи cdвыходить, но меня просто интересуют возможности отказаться от лишних шагов :)

Нафтули Кей
источник
Это довольно тривиально , чтобы сделать скрипт , который делает это: echo "#!/bin/bash; cd $1; exec $2" > /usr/local/bin/execindirectory; chmod +x /usr/local/bin/execindirectory. Возможно, потребуется приложить немного больше усилий, если вы хотите, чтобы он действительно поддерживал опцию "тегов", таких как -dи прочее.
LawrenceC
Как неизвестный пользователь заявляет в ответе, все примеры, которые вы приводили здесь и в комментариях, лучше рассматриваются другими решениями, поэтому неясно, существует ли на самом деле проблема, которая требует решения здесь. Можете ли вы придумать лучший пример?
Калеб

Ответы:

55

Я не знаю, считается ли это, но вы можете сделать подоболочку:

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

Каталог изменяется только для этой подоболочки, поэтому вы можете избежать необходимости в cd -последующем.

Михаил Мрозек
источник
2
Это то, что я обычно делаю.
Адам Быртек
Здорово, я совсем забыл о субоболочках, что очень удобно в этом случае.
Нафтули Кей
4
Для того, чтобы избежать возможного хаоса, к югу из запятой с двумя амперсандами: $ (cd /var/log && cp *.log ~/Desktop). Таким образом, если каталог не существует, дальнейшие команды не выполняются.
Нафтули Кей
Заметьте, для кого-то еще такого же наивного, как я: $ в начале не является частью команды, только все после нее.
Maltronic
14

У некоторых программ есть опции, с помощью которых вы можете сказать им самим chdir (2) (например, GNU tar 's -C/ --directory).

За пределами таких программ что-то придется чдир . Вы могли бы написать и использовать какую-то скомпилированную «двоичную» программу вместо того, чтобы оболочка делала это, но это, вероятно, не принесло бы большой пользы.

В комментарии к другому ответу вы привели пример:

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

Так как *.logшаблон расширяется самой оболочкой (не cp ), что-то должно будет chdir в каталог, прежде чем оболочка оценит вашу команду.

Если вам просто интересно избегать «cd back», то вы можете использовать подоболочку, чтобы изолировать эффект cd от вашего рабочего экземпляра оболочки.

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

Вы можете упаковать это в функцию оболочки. (Я исключил эту -dопцию из вашего примера использования, поскольку эта команда не имеет смысла, если каталог на самом деле необязательный.)

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
Крис Джонсен
источник
2
Мне нравится это решение, за исключением того, что лично я бы использовал pushd / popd
NJ
10

Не для того, чтобы подорвать ценность ответов, данных другими людьми, но я верю, что вы хотите вот что:

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

Обратите внимание на парены, которые нужно вызывать cdв под-оболочке.

Алекс
источник
Я так не думаю. Как я понимаю, он хочет попасть в начальный каталог.
Адам Быртек
О, я совершенно забыл обернуть это в подоболочку. Исправил мой ответ, спасибо.
Алекс
4

Вот кое-что, что должно cdвернуть вас туда, где вы были (используя Bash), так как цель этого вопроса - не забыть сделать это:

# 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

(РЕДАКТИРОВАТЬ: немного короче версия, благодаря @ Random832)

Bruno
источник
1
Вы могли бы просто pushd other-dir, а неpushd .; cd other-dir
Random832
@ Random832, хорошая мысль!
Бруно
2

К сожалению, ваш пример:

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

не нужно менять каталог, потому что

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

сделал бы то же самое. Разве вы не можете приблизиться к своей реальной проблеме? Потому что мы могли бы знать и лучшее решение для этого.

Сложным способом решения вашей проблемы, который далек от элегантности решения Michaels, является использование команды find, которая имеет ключ '-execdir', который должен выполняться в директории, где находится файл. Плохо принят по вашему примеру:

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

Может быть, это полезно для вашей реальной проблемы. -okdir вместо -execdir попросит вас подтвердить каждый вызов.

-okdir и -execdir, возможно, потребуется установить gnu-find, который обычно используется в Linux.

неизвестный пользователь
источник
1

Как насчет ./your/path/command.sh?

bdictator
источник
Нет, я на самом деле имел в виду что - то вроде следующего: execindirectory -d /var/log "cp *.log ~/Desktop".
Нафтули Кей
Я прекрасно понимаю, что это не является строго необходимым, кстати, мне просто интересно, можно ли это на самом деле сделать.
Нафтули Кей