2014-04-02 11 views
2

Я понимаю, что с | инициирует новый процесс для команды (ы) после трубы, любая команда оболочки формы cmd | cd newdir (где cmd не изменяет текущий рабочий каталог) будет оставить рабочий каталог исходного процесса в неизменной. (Не говоря уже о том, что это немного глупо, так как cd не считывают данные из стандартного ввода.)Трубопровод `cd` или` popd` выход предотвращает изменение каталогов?

Однако на моей машине (а CentOS 6 коробки, используя bash, ksh или zsh), представляется, что следующее команда также не удается изменить каталоги:

cd newdir | cat 

(Пожалуйста, игнорируйте, как глупо это для вывода труб кошке здесь, я просто пытаюсь сделать простой пример.)

Почему это? Есть ли способ обойти эту проблему? В частности, я пытаюсь написать псевдоним, который использует popd, но ловит вывод, отбрасывает stdout и повторно выводит stderr.

(Для любопытных, это мой текущий, нерабочий псевдоним:.. popd 2>&1 >/dev/null | toerr && lsd Здесь toerr просто ловит стандартный ввод, выводят его на стандартный вывод ошибки и возвращает число прочитанных строк/распечатан lsd является каталог-name- который должен выполняться только при успешном завершении popd. Причина, по которой я отправляю stderr в stdout, обманывать его, ловить его и повторно выводить на stderr, это просто сделать его красным, используя stderred, так как моя оболочка сессия не загружена LD_PRELOAD, так Баш встроенные модули, такие как popd не получить красный цвета STDERR.)

+1

В ответ на то, кто голосует, чтобы закрыть это, потому что это вне темы: во-первых, эта проблема применяется как к сценариям оболочки, так и к интерактивным сеансам оболочки; во-вторых, проблема возникает в контексте написания псевдонима, который (особенно в этом случае, когда у меня есть относительно сложная логика) по существу является крошечной программой; –

+0

Третий вопрос по темам о процессах и подпроцессах на SuperUser имеет тенденцию больше фокусироваться на взаимодействии пользователя с запущенными процессами (просмотр/убийство заданий, процессы нереста и т. Д.), В то время как этот вопрос касается технического поведения '|', который кажется Мне больше нравится программирование. –

ответ

2

bash В, dash и ash, каждый из которых совместно мм и в конвейере работает в подоболочке.

В zsh, ksh и bash с shopt -s lastpipe, все, кроме последней команды в перспективе трубопровода в подоболочках.

С cd - а также переменные, опции оболочки, ulimits и новые дескрипторы файлов - влияет только на текущий процесс, их эффекты не будут влиять на родительскую оболочку.

Примеры:

# Doesn't change directory 
cd foo | cat 
pwd 

# Doesn't set $bar on default bash (but does on zsh and ksh) 
echo foo | read bar 
echo "$bar" 

# Doesn't change the ulimit 
ulimit -c 10000 2>&1 | grep "not permitted" 
ulimit -c 

То же самое относится и к другим вещам, которые генерируют подоболочки. Ни один из следующих не изменит каталог:

# Command expansion creates a subshell 
echo $(cd foo); pwd 

# (..) creates a subshell 
(cd foo); pwd 

# Backgrounding a process creates a subshell 
cd foo & pwd 

Чтобы исправить это, вы должны переписать код, чтобы запустить что-нибудь, что влияет на окружающую среду в основном процессе оболочки.

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

popd > /dev/null 2> >(toerr) && lsd 

Это имеет дополнительное преимущество, только работает, когда lsdpopd успешно, а не когда toerr успешно как ваша версия делает.

+0

Так что я имел это в обратном порядке, так как я думал, что в случае, когда одна команда в конвейере находится в текущем процессе, команда * first * является той, которая * не * в подоболочке, но на самом деле это * последний * команда, выполняемая в текущем процессе? –

+0

В любом случае, спасибо за альтернативное предложение, а также за другие незначительные исправления (хотя я не уверен, почему '2> & 1' и' 2> 'ведут себя по-другому). Тем не менее, небольшая коррекция - ваша версия использует замещение процесса, а не подстановку команд. –

+0

Это последний (если есть), да. Разница между '2> & 1>/dev/null | toerr' и '2>> (toerr)' в основном избегают трубы. Они оба отправляют команду stderr на stdin toerr. –

 Смежные вопросы

  • Нет связанных вопросов^_^