Временно изменить каталог для одной команды пакетного файла

22075
Greg

В сценариях оболочки, если мне нужно запустить команду из каталога, я могу использовать подоболочку, чтобы вернуться в исходный контекст:

(cd temporary/new/directory ; command) # now I am still in original directory 

Это можно сделать в пакетных файлах Windows (или cmd-файлах)

То же самое в пакетных файлах оставляет меня в новом каталоге.

Я могу сделать:

pushd temporary\new\directory && command && popd 

Но попд зависит от успеха command.

Есть идеи?

17
Как вы вызываете свой «пакетный файл» или «cmd-файл»? Если вы поместите команду cd в сценарий оболочки и выполните этот сценарий (а не его исходный код), текущий рабочий каталог вызывающей оболочки не изменится. garyjohn 13 лет назад 0
Просто чтобы прояснить это относится к пакетным файлам Windows. Greg 13 лет назад 0
Это скрипт, который запускает кучу команд в разных частях дерева каталогов. Некоторые из команд работают только с текущим каталогом. Возврат в исходный каталог помогает упростить данные, которые управляют сценарием. Вы предлагаете создать отдельный пакетный файл для каждой директории, в которой мне нужно совершать звонки? Greg 13 лет назад 0
Насколько я помню, вы ссылались на сценарии оболочки и не упоминали Windows в своем первоначальном вопросе, поэтому я ошибочно предположил, что вы используете Unix-подобную систему. Теперь я понимаю. garyjohn 13 лет назад 0
Да, извините, я понимаю, что я не был ясен (хотя я думаю, что 'пакетный файл' был подсказкой :-p) Greg 13 лет назад 0

6 ответов на вопрос

20
BillP3rd

Если вы делаете:

pushd \windows && foobar && popd 

Вы останетесь (как вы заявляете) в папке \ windows. Пытаться:

pushd \windows & foobar & popd 

и ты должен вернуться туда, откуда начал.

Ах, так один амперсанд является эквивалентом точки с запятой в ш. Отлично. (и ссылка: http://ss64.com/nt/syntax-conditional.html) Greg 13 лет назад 1
Хорошо помнить, что `cd` /` pushd` иногда дает сбой (например, если каталог не существует). `pushd \ windows && (foobar & popd)` может быть более надежным grawity 13 лет назад 5
13
grawity

По умолчанию пакетные файлы Windows запускаются в контексте родительской оболочки (что необычно для пользователей Unix, где требуется явное source, но было единственной возможностью в MS-DOS). Это означает, что изменения каталога и переменные среды также влияют на оригинальную интерактивную оболочку.

Поместите его setlocalв верхнюю часть скрипта, чтобы он работал в своем собственном контексте - тогда вы можете безопасно использовать его cdвнутри скрипта.

Спасибо, это звучит как то, что мне нужно - я проверю это, когда получу доступ к машине с Windows. Повлияет ли это на подкоманды с использованием скобок? Greg 13 лет назад 0
@Greg: Кажется, что `(` `)` только группируют команды, но все же запускают их в родительском контексте. `(setlocal & cd foo & bar)` не будет работать; вместо этого потребуется `pushd foo && (bar & popd)`. grawity 13 лет назад 1
3
bahamat

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

$ pwd /etc $ cd /var ; pwd ; cd - /var $ pwd /etc 
Я обновил вопрос, чтобы уточнить, что я спрашиваю о пакетном сценарии для Windows / shell. Я знаю, как сделать это под sh-like оболочкой :) Greg 13 лет назад 0
Как BillP3rd указал эквивалент ';' в пакетных файлах есть '&'. Greg 13 лет назад 0
Ах, прости. Ваше использование слэшей заставило меня думать, что это UNIX. bahamat 13 лет назад 0
3
Timtech

Как упоминалось ранее, это pushd \windows && (foobar & popd)будет работать лучше, чем pushd \windows & foobar & popdпотому, что последний может потерпеть неудачу, если такой директории нет.

Кроме того, используя setlocalи endlocalпозволяет вам иметь несколько локальных сред, например, вы можете иметь:

setlocal

cd dir

command

endlocal

Теперь вы вернетесь в исходный каталог.

1
Scott

Я приветствую предложение Гравити поставить setlocalв начале вашего пакетного скрипта, но я бы добавил тот факт, что вы можете иметь несколько вложенных блоков setlocal/ endlocal, так что более уместным ответом на вопрос может быть

@echo off
setlocal
cddir1
  ...
setlocal
cddir2
command
endlocal
:: Now I am back indir1
  ...

И, конечно же, если вы хотите, чтобы команда выполнялась только в том случае, если cdto dir2успешно, скажем .cddir2&&command

Обратите внимание, что блок setlocal/ endlocalсоздает локализованную среду, поэтому любые переменные, которые вы устанавливаете или изменяете в таком блоке, возвращаются к своему предыдущему значению после endlocal.

0
surfasb

Вы можете сохранить текущий каталог в переменную. Измените и измените обратно в зависимости от возвращаемого значения команды. Кстати,% CD% возвращает ваш текущий DIR.