Как я могу добавить каталог для СОЕДИНЕНИЯ КАНАЛОМ в сценарии так, чтобы он влиял на оболочку вызова и остальную часть сессии?

Я плохо знаком с Ubuntu.

Я записал сценарий для добавления dir к среде ПУТИ. Когда я запускаю скрипт, он хорошо работает, и dir добавляется к ПУТИ. Но кажется, что изменение только длится до выходов сценария вместо того, чтобы длиться в течение продолжительности сессии. То, когда я смотрю на ПУТЬ после того, как сценарий, работало, dir больше не там. Какие-либо предложения?

2
задан 10 September 2018 в 10:35

2 ответа

Существует две вещи помнить:

  1. Команды, включая сценарии, сохраняют свою среду на время выполнения команды

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

Таким образом, если Вы делаете PATH=$PATH:/my/dir это только продолжится в период сценариев. Для создания этого постоянным родительская оболочка должна знать об изменении. Надлежащий способ сделать, который должен был бы записать в ~/.bashrc если Вы используете удар или соответствующий емкостно-резистивный файл для Вашей оболочки. Таким образом мы можем использовать>> для добавления в файл

echo PATH=$PATH:/my/dir >> ~/.bashrc

И когда сценарий выходит, выполненный

source ~/.bashrc

так, чтобы оболочка перечитала конфигурацию и знала об изменениях. Теперь каждая команда, которую Вы выполняете в оболочке и каждой новой интерактивной запущенной оболочке, наследует новую переменную ПУТИ

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

2
ответ дан 2 December 2019 в 02:41

Ответ Sergiy Kolodyazhnyy определяет проблему здесь: сценарии выполняются в отдельной дочерней оболочке оболочки, которая называет их и управляет, чтобы влияли на саму оболочку, такую как присвоение переменным или изменение рабочего каталога, не влияйте на оболочку вызова вообще, только дочерняя оболочка и (если они export переменные к среде) ее дети.

Можно играть с этим использованием скромные переменные оболочки...

$ foo=bar
$ echo $foo
bar
$ echo -e "foo=baz \n"'echo $foo' > script
$ cat script
foo=baz 
echo $foo
$ bash script
baz
$ echo $foo
bar

Хотя, поскольку Eliah Kagan показывает в этом ответе, легче сделать так с подоболочками.

Я пишу этот ответ в случае, если Вы не хотите постоянно добавлять каталог к своему ПУТИ, но только к текущей сессии оболочки.

Чтобы сделать это, просто необходимо запустить скрипт в текущей оболочке. Это, покончили source команда, которая сокращена до . (точка).

Учитывая эту немного упрощенную версию Вашего сценария...

read -rp "What did you want to add to PATH? "
[ -d "$REPLY" ] && 
PATH="$PATH:$(readlink -m $REPLY)" &&
echo "OK, adding $REPLY to PATH" &&
echo "$PATH" ||
echo "seems like $REPLY is not a directory"

Заметьте, что я получаю тот же результат как Вы, когда я запускаю скрипт обычным способом:

$ ./add-to-path
What did you want to add to PATH? /home/zanna/playground
OK, adding /home/zanna/playground to PATH
/home/zanna/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/zanna/playground
$ echo $PATH
/home/zanna/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

Но когда я source сценарий это работает как ожидалось:

$ . add-to-path
What did you want to add to PATH? /home/zanna/playground
OK, adding /home/zanna/playground to PATH
/home/zanna/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/zanna/playground
$ echo $PATH
/home/zanna/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/zanna/playground

Я добавлю три азида:

  • Я рекомендую добавить присвоения ПУТИ на ~/.profile вместо ~/.bashrc потому что ~/.bashrc получен каждой интерактивной оболочкой Bash, включая оболочки, запущенные с текущей оболочки - это означает, что дочерние оболочки могли закончиться с действительно длинными трактами, поскольку они наследовали ПУТЬ, а также добавляющий к ней, когда они получают ~/.bashrc. Напротив, ~/.profile обычно только получается при входе в систему (или оболочками входа в систему).
  • Вы не должны export когда Вы присваиваете ПУТИ, потому что это уже - переменная среды: в некотором смысле это уже экспортировано и останется так: присвоение на ПУТЬ будет всегда наследовано дочерними процессами (хотя не родительских процессов, поскольку Вы обнаружили!), не будучи явно exportредактор.
  • Я заключил переменные в кавычки REPLY и PATH повсюду. Это - хорошая идея, потому что или может иметь пробелы или другие символы та триггерная оболочка расширения. Однако побочный эффект этого - это ~ не расширен, таким образом, сценарий склонен возвратить вещи как

    looks like ~/some-existing-dir is not a directory
    

    который верен (взятие ~ буквально), но не очень полезный. Возможно, сценарий должен предупредить пользователя об этом...

1
ответ дан 2 December 2019 в 02:41

Другие вопросы по тегам:

Похожие вопросы: