Важно помнить о 2-х таких вещах как:
- Команды, включая сценарии, сохраняют свою среду на время выполнения команды
- Команды наследуют среду от родительского процесса и для команд, запускаемых через оболочку, они наследуются от оболочки.
Так что, если вы это сделаете
PATH=$PATH:/my/dir
то это продлится только в течение сценариев. Чтобы сделать его постоянным, родительская оболочка должна знать об изменениях. Правильный способ сделать это - написать
~/.bashrc
если вы используете bash или соответствующий rc-файл для вашей оболочки. Таким образом, мы можем использовать >> для добавления в файл
Сделайте вот так:
echo PATH=$PATH:/my/dir >> ~/.bashrc
И когда скрипт выйдет, запустите
source ~/.bashrc
Теперь оболочка будет в курсе изменений и каждая команда, которую вы запускаете в командной оболочке, а также каждая новая запущенная интерактивная оболочка, наследует новую переменную PATH.
Эти два шага могут быть объединены в функцию, поскольку для bash функции выполняются в текущей среде оболочки, поэтому в отличие от скрипта, когда вы выполняете source часть, вызов source из функции повлияет на текущую оболочку.
Это определяет проблему.
Вы можете манипулировать, используя простые переменные оболочки.
$ 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
Хотя может и проще это делать при помощи подоболочек. На тот случай, если вы не хотите постоянно добавлять каталог в PATH, а только в текущий сеанс оболочки, вам просто нужно запустить скрипт в текущей оболочке . Это делается с помощью 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
Но когда применяем sourse, все работает как положено
$ . 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
Можно подвести итог.
- Лучше добавлять назначения PATH ~/.profileс чем ~/.bashrc потому, что ~/.bashrc поставляются каждой интерактивной оболочкой Bash, включая оболочки, запускаемые из текущей оболочки - это означает, что дочерние оболочки могут заканчиваться очень длинными PATH, поскольку они наследуют PATH, а также добавляются к нему, когда исходный текст ~/.bashrc, в отличие от этого ~/.profile обычно поступает только при входе в систему.
- Присваивание PATH всегда будет наследоваться дочерними процессами,но не родительскими процессами, без явного export редактирования.
- Проецирование переменных REPLYи PATH является хорошей идеей, поскольку могут быть пробелы или другие символы, которые запускают расширения оболочки.
- Недостатком является то, что ~ не расширяется, поэтому сценарий может возвращать, к примеру, такие вещи, как
looks like ~/some-existing-dir is not a directory