У меня есть сценарий, который требует подстановки команд без использования подоболочки. У меня есть такая конструкция:
pushd $(mktemp -d)
Теперь я хочу выйти и удалить временный каталог за один раз:
rmdir $(popd)
Однако это не работает, потому popd
что не возвращает перенесенный каталог (он возвращает новый, теперь текущий, каталог), а также потому, что он выполняется в подоболочке.
Что-то типа
dirs -l -1 ; popd &> /dev/null
вернет извлеченный каталог, но его нельзя использовать так:
rmdir $(dirs -l -1 ; popd &> /dev/null)
потому что popd
будет влиять только на подоболочку. Для этого требуется способность сделать это:
rmdir { dirs -l -1 ; popd &> /dev/null; }
но это неверный синтаксис. Возможно ли добиться этого эффекта?
(примечание: я знаю, что могу сохранить временный каталог в переменной; я пытался избежать необходимости делать это и учиться чему-то новому в процессе!)
trap
обработчик может очистить каталог, если процесс будет обработан сигналом.fish
, эквивалент подстановки команд()
, изменяет папку внешней оболочки. Это обычно раздражает, но в таких случаях это полезно, я уверен.Ответы:
Выбор названия вашего вопроса немного сбивает с толку.
pushd
/popd
,csh
функция, скопированнаяbash
иzsh
, является способом управления стеком запомненных каталогов.помещает текущий рабочий каталог в стек, а затем изменяет текущий рабочий каталог (а затем печатает,
/some/dir
а затем содержимое этого стека (через пробел).печатает содержимое стека (опять же разделенное пробелами), а затем переключается на верхний элемент стека и извлекает его из стека.
(также помните, что некоторые каталоги будут представлены там с их
~/x
или~user/x
обозначениями).Так что если в стеке в данный момент есть
/a
и/b
, текущим каталогом является/here
и вы работаете:pushd
будет печатать/tmp/whatever /here /a /b
иpopd
выводить/here /a /b
, а не/tmp/whatever
. Это не зависит от использования подстановки команд или нет.popd
не может использоваться для получения пути к предыдущему каталогу, и, как правило, его выходные данные не могут быть обработаны после обработки (см. массив$dirstack
или$DIRSTACK
некоторые оболочки, хотя для доступа к элементам этого стека каталога)Может быть, вы хотите:
Или
Хотя я бы использовал:
В любом случае,
pushd "$(mktemp -d)"
не работаетpushd
в подоболочке. Если это так, он не может изменить рабочий каталог. Это то,mktemp
что работает в подоболочке. Поскольку это отдельная команда, она должна выполняться в отдельном процессе. Он записывает свой вывод в канал, а процесс оболочки читает его на другом конце канала.ksh93 может избежать отдельного процесса, когда команда встроена, но даже там, это все еще подоболочка (другая рабочая среда), которая на этот раз эмулируется, а не полагается на отдельную среду, обычно предоставляемую разветвлением. Например, в
ksh93
,a=0; echo "$(a=1; echo test)"; echo "$a"
вилка не задействована, но все равноecho "$a"
выводится0
.Здесь, если вы хотите сохранить выходные данные
mktemp
в переменной, в то же время, когда вы передаете ееpushd
, с помощьюzsh
, вы можете сделать:С другими подобными Борну оболочками:
Или использовать вывод
$(mktemp -d)
несколько раз без явного сохранения его в переменной, вы можете использоватьzsh
анонимные функции:источник
pushd
иpopd
работаю так, как вы описываете, и что они не зависят от подстановки команд - здесь нет путаницы! Тем не менее, вы ответили собственной проблемой, раскрывая$OLDPWD
. Я могу сделатьpopd; rmdir $OLDPWD
. Это ответ на мою проблему - все остальное только подтверждает то, что я думал. Подстановка команд, кажется, является способом ее решения, но это не из-за подоболочки, и вы не можете выполнить подстановку команд без подчиненной оболочки, так что спасибо за раскрытие OLDPWD - это именно то, что мне нужно!rmdir $(popd)
заставляетpopd
работать в под-оболочке, что означает, что он не изменит текущий каталог, но даже если он не был запущен в подоболочке, выводpopd
не будет временным каталогом, это будет список, разделенный пробелами каталогов, не включая этот временный каталог. Вот где я говорю, что ты в замешательстве.OLDPWD
. Я должен помнить, чтобы один день читатьman bash
от начала до конца!Вы можете отсоединить каталог, прежде чем покинуть его:
или
но обратите внимание , что
pushd
иpopd
на самом деле инструменты для интерактивных оболочек, а не для скриптов (именно поэтому они столь разговорчивы; команды реальных сценариев молчат , когда им удается).источник
В bash
dirs
предоставьте список запомненных каталогов методом pushd / popd.Также
dirs -1
печатает последний каталог, включенный в список.Итак, чтобы удалить каталог, созданный ранее путем выполнения
pushd $(mktmp -d)
, используйте:И тогда
popd
уже удаленный каталог из списка:Все в одной строке:
И добавив опцию (-l), чтобы избежать обозначения
~/x
или~user/x
:Что удивительно похоже на строку, которую вы просили.
За исключением того, что я не буду использовать,
&>
поскольку он будет скрывать любые сообщения об ошибкахpopd
.Примечание. Каталог останется после того,
rmdir
как он будетpwd
в этой точке. И будет фактически не связан послеpopd
команды (оставшиеся ссылки не используются).Существует возможность использовать для оболочек, которые поддерживают переменную «OLDPWD» (большинство оболочек типа bourne: ksh, bash, zsh have
$OLDPWD
). Интересно отметить, что ksh не реализует dirs, pod, pushd по умолчанию (lksh, dash и другие также не имеют popd, поэтому здесь их нельзя использовать):Или, более идиоматический (тот же список оболочек, что и выше):
источник
rmdir
текущий каталог, в котором вы находитесь, когда будете это делать. Вы должны выполнить действие,popd
прежде чем делать,rmdir
но вам нужно знать, что удалить, иpopd
не говорит вам об этом. Я, как и вы, думал,dirs -l -1
что ответ был, но с тех пор обнаружил, что ответ на самом деле использовать$OLDPWD
.popd && rmdir ~-
.rmdir "$PWD"
все в порядке. Кроме того, текущий каталог должен быть тем, который был созданmktmp -d
(если онpushd $(mktemp -d)
был выполнен заранее) и в которыйpushd
перемещается pwd. Итак, да, послеpushd
и до popd, созданный каталог сохраняется$(dirs -1)
, я не вижу никаких проблем.