Почему «cd» не работает в сценарии оболочки?


43

Я просто хочу написать скрипт, который меняет мой каталог .

Я положил следующие команды в файл /home/alex/pathABC

#!/bin/sh
cd /home/alex/Documents/A/B/C
echo HelloWorld

Я сделал chmod +x pathABC.

В терминале, в то время как в /home/alex, я бегу ./pathABC, но вывод просто HelloWorldи текущий каталог не изменяется.

Так что не так?


Ответы:


74

Как объяснили другие, каталог изменяется в дочернем процессе вашего скрипта, а не в терминальном процессе, из которого вызывается скрипт. После того, как дочерний процесс умирает, вы возвращаетесь в терминал, который остался там, где он был.

Несколько альтернатив:

1. Символическая ссылка

Поместите символическую ссылку в вашем доме на длинный путь, который вы хотите легко получить доступ

$ ln -s /home/alex/Documents/A/B/C ~/pathABC

затем получить доступ к каталогу с помощью:

$ cd ~/pathABC

2. Псевдоним

Поместите псевдоним в ваш ~ / .bashrc:

alias pathABC="cd /home/alex/Documents/A/B/C"

( отсюда )

3. Функция

Создайте функцию, которая изменяет каталог, функция запускается в процессе работы вашего терминала и затем может изменить свой каталог.

( отсюда )

4. Избегайте бега в детстве

Источник ваш сценарий вместо того, чтобы запустить его. Sourcing (выполняется с помощью .или source) приводит к тому, что скрипт выполняется в той же оболочке, а не в своей собственной подоболочке.

$ . ./pathABC

( отсюда и здесь )

5. CD-способные Vars

Установите cdable_varsпараметр в вашем ~/.bashrcи создайте переменную окружения для каталога:

shopt -s cdable_vars
export pathABC="/home/alex/Documents/A/B/C"

Тогда вы можете использовать cd pathABC

( отсюда )


15
Теперь я понимаю использование source! Я всегда задавался вопросом, почему я делаю, source .bashrcа неbash .bashrc
hytromo

Вариант 3 работал отлично. Я только что определил функцию go_to_wherever () {cd my / directory} в начале моего скрипта. Вызывается перед запуском операций в этом каталоге.
i2097i

> 5. CD-способные VARS - не так ли cd $pathABC?
loxaxs

7

Когда вы запускаете скрипт в терминале, запускается дочерний процесс. В этой дочерней программе, т. Е. Ваш сценарий изменится на любой указанный каталог. Но в родительском процессе, то есть в том месте, где вы запускаете скрипт, он все еще находится на старом пути. ИЛИ просто мы можем сказать:

The scope of cd command is only for child process not parent


2
В добавление к этому, @alex для достижения эффекта, который вы ищете, выполните сценарий в родительском процессе, используя его: либо, . pathABCлибо source pathABC.
zwets

4

Вы делаете ошибку мышления. Пока текущая оболочка находится в том же каталоге, сценарий перемещен в новый каталог.

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

#!/bin/sh
cd /home/alex/Documents/A/B/C && ./another_script.sh # (if it is executable)

Второй скрипт будет запускаться из нового каталога.

HelloWorld 

это просто вывод скрипта.


3
HelloWorld не «возвращается» в родительскую оболочку, он выводится на стандартный вывод
Mog

Возможно, будет понятнее, если вы просто запустите pwdновый каталог, вместо того, чтобы добавлять в ситуацию совершенно новый сценарий.
wjandrea

0

Поскольку hello world - это просто след, давайте попробуем это:

Создайте файл сценария bash, cd.shсодержащий:

#!/bin/bash
echo "/home/mike/Documents/A/B/C"
  • .shРасширение старой конвенции дает Баш скрипт для имен файлов расширения. Это чисто косметическое и обычно ненужное. Однако в этом случае важно отличаться от основной cdкоманды.

Отметьте исполняемый файл bash-скрипта, используя:

chmod a+x cd.sh

Теперь запустите файл:

$ cd $(./cd.sh)
bash: cd: /home/alex/Documents/A/B/C: No such file or directory
  • cd мы все знаем.
  • $(...) выполняет команду в круглых скобках и возвращает вывод.
  • Если он cd.shбыл на вашем пути, вам не нужно указывать, где он находится. Мы префикс с, ./чтобы указать, что команда находится в текущем каталоге.
  • echoВыход из cd.shсценария отправляется обратно к родителю через $(...). Родитель (наша подсказка оболочки) использует этот вывод и передает его команде Linux cd.

Как уже упоминали другие, дочерний процесс не может изменить каталог родителя. Это один из способов, которым ребенок может сказать родителю, куда идти после завершения процесса.


@wjandrea Вот что вы получаете за кодирование на телефоне! Просто приехал домой, я все исправлю. Спасибо. Гм только что проверил, и все работает отлично. Может быть, это твоя 14.04версия, которую я прочитал около часа назад или около того?
WinEunuuchs2Unix

Ну, вы полностью изменили сценарий. Ранее это была всего лишь одна команда:, cd /home/mike/Documents/A/B/Cкоторая не производила никакого вывода. Теперь это echo "/home/mike/Documents/A/B/C", который производит продукцию.
января

@wjandrea Правда, я тоже полностью изменил способ вызова скрипта. Вместо простого ./cd.shэто сейчас, cd $(./cd.sh)но оно выполняет задачу дочернего элемента, изменяя текущий каталог родителя. Да, это нетрадиционно, но это еще один способ сделать это, я надеюсь, что люди найдут интересным.
WinEunuuchs2Unix
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.