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

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

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

#!/bin/shcd /home/alex/Documents/A/B/Cecho HelloWorld

Я сделал

chmod +x pathABC

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

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

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

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

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. Избегайте бега как ребенок

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

$ . ./pathABC

(из здесь и здесь)

5. вары, поддерживающие компакт-диски

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

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

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

(из здесь)

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

Область действия команды cd предназначена только для дочернего процесса, а не для родительского.

Вы совершаете мыслительную ошибку. В то время как текущая ракушка остается в том же каталоге, то скрипт переместился в новый каталог.

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

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

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

HelloWorld 

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

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

(cd your_dir; do_some_command_there)

Например, то, что мне нужно было использовать, было:

(cd your_dir; git remote -v | wc -l)

Работает как заклинание!

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

Чтобы добиться изменения каталога, используйте sourcing.Вы можете либо использовать . scriptname.sh или source scriptname.sh команда для использования источника.

Примечание: Также, когда вы используете sourcing, не используйте команду exit, потому что она затем закрывает ваше соединение.

Воспользуйся $SHELL в конце

Сценарий bash работает в своей текущей среде или в среде своих дочерних элементов, но никогда в своей родительской среде.

Однако этот вопрос часто задают, потому что кто-то хочет чтобы быть оставленным в командной строке в определенном каталоге после выполнения скрипта из другого каталога.

Если это так, просто казнить ребенка $SHELL пример в конце сценария:

# !/usr/bin/env bashcd /home/alex/Documents/A/B/Cecho -e '\nHit [Ctrl]+[D] to exit this child shell.'$SHELL

Чтобы вернуться к предыдущему, родительскому экземпляру оболочки, используйте Ctrl+D.

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

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

#!/bin/bashecho "/home/mike/Documents/A/B/C"
  • То .sh расширение - это более старое соглашение о предоставлении именам файлов сценариев bash расширения. Это чисто косметическое средство и обычно в нем нет необходимости. Однако в этом случае важно отличать его от основного 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 команда.

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

CDPATH может помочь в некоторых случаях.

# add this to .bashrc .zshrc or whateverexport CDPATH="/home/alex/Documents/A/B:$CDPATH"# and then you can just do...cd C

Обратите внимание, что вы должны добавить 'A / B' в CDPATH, а не 'A /B / C'. Вы можете добавить несколько путей к CDPATH точно так же, как PATH.

Посмотрите на это Почему “cd” не работает в сценарии оболочки bash?

‘cd’ работает в сценарии оболочки. Например, вы могли бы поместить любой скрипт в путь /home/alex/Documents/A/B/C и написать сценарий оболочки следующим образом: сначала он перейдет в каталог (через cd), затем запустите скрипт (через ./), затем он будет. Однако после этого элемент управления вернется обратно к текущему пути, с которого вы запускаете скрипт ./pathABC. Тот же случай происходит и с вашим скриптом, он переходит к пути, а затем, как только выполнение завершается, он возвращается обратно в то место, откуда он был вызван.