Почему «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

Tingrammer
источник
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.

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

WinEunuuchs2Unix
источник
@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