Не удается успешно получить исходный код .bashrc из сценария оболочки

51

Обычно мы можем получить исходный ~/.bashrcфайл с помощью этой команды

source ~/.bashrc

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

Мой сценарий:

#!/bin/bash
chmod a+x ~/.bashrc
source ~/.bashrc

Также попробовал .(точка) вместо source. Тот же результат.

Шантану
источник

Ответы:

26

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

sourceКоманда, напротив , не запускает новый экземпляр оболочки, а использует текущую оболочку, поэтому изменения остаются.

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

alias brc='source ~/.bashrc'
Флориан Диш
источник
Спасибо за ваш быстрый ответ. Возможно, ваше решение работает, но мне нужно отредактировать файл bashrc вручную, чтобы сохранить строку 'aliac brc = ....'. Я пытаюсь разработать графический интерфейс для изменения переменной среды. Поэтому я не могу редактировать файл bashrc другого компьютера вручную.
Shantanu
1
Вы должны работать source ~/.bashrcв оболочке, из которой вы хотите изменить среду. Вы не можете изменить его из другого процесса. Возможно (глобально) добавление этого псевдонима может быть частью процесса установки вашего GUI.
Флориан Диш
1
поэтому я помещаю вашу команду псевдонима ранее в сценарий и затем вызываю brc, когда я хочу получить исходный код .bashrc, или мне нужно поместить эту команду псевдонима в файл где-нибудь?
user137717
В итоге я продолжил ответ Флориана Диша. Вы можете просто использовать многострочный псевдоним: alias brc = 'chmod a + x ~ / .bashrc; source ~ / .bashrc «Я все еще новичок, поэтому я не уверен, считается ли это« плохой практикой ». Это работает, хотя.
A_user_appears
13

Ваш .bashrcобычно начинается:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

Поскольку ваш сценарий не имеет установленного PS1 (потому что он не интерактивный), он не сбрасывает путь, потому что он выходит рано. Чтобы продемонстрировать, измените ваш скрипт:

    #!/bin/bash
    chmod a+x ~/.bashrc
    PS1='$ '
    source ~/.bashrc

теперь это позволит вашим скриптам работать с новым .bashrc. Примечание: как только ваш скрипт завершится, env будет установлен на то, что было до запуска скрипта. Изменения будут отражены при следующем запуске терминала.

рави нанкани
источник
По крайней мере, с 16.04 и, возможно, до этого Ubuntu по умолчанию .bashrcиспользует более надежный способ проверить, является ли оболочка интерактивной. /etc/bash.bashrcвсе еще имеет тест PS1.
Занна
12

Пытаться:

exec bash

Это должно перезагрузить ~ / .bashrc, ~ / .bash_aliases и т. Д.

Алин Андрей
источник
9
Это заменяет текущий процесс bash новым. Это не намного короче и не проще, чем использование, sourceно уничтожает любые переменные и такие, которые пользователь установил вручную - что может или не может быть то, что вы хотите.
Флориан Диш
подождите, в контексте сценария Shell с другими командами после получения bashrc, вы помещаете команды, которым необходимо новое состояние bash после этого exec bash, как я понимаю, команда после этого все еще будет в тех же настройках bash, что и раньше?
Тацу
11

Я хочу дополнить ответ Рави :

Такое поведение характерно для Ubuntu (и, вероятно, большинства производных дистрибутивов), поскольку ваш ~/.bashrcфайл по умолчанию начинается с короткого замыкания, Ubuntu 18.04, например:

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

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

eval мотыга

Я обнаружил уродливый хак для обхода Ubuntu специально, используя evalвместо source:

eval "$(cat ~/.bashrc | tail -n +10)"

Он просто пропускает несколько первых строк и оценивает оставшуюся часть, ~/.bashrcпоэтому остальные оцениваются и изменяют текущее выполнение.

Имейте в виду, что это магическое число, которое может не работать во всех версиях Ubuntu; но может быть хорошим решением, если вы создаете сценарии для более или менее известных систем.

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

Альтернатива Шебангу

Другая альтернатива, которая может работать лучше в некоторых сценариях, - заставить скрипт запускаться в интерактивной оболочке, добавив флаг в shebang :

#!/bin/bash -i

Помните о нескольких вещах:

  • Это лучше практика использовать #!/usr/bin/env bashформу , но таким образом , вы не можете запустить оболочку с аргументами .
  • Использование -iимеет свой собственный набор последствий, среди которых программы будут запрашивать взаимодействие с пользователем, и это обычно не предназначено для сценариев, например, установка debпакетов может остановить сценарий при dpkg configureзапросах .
  • Сначала я пытался использовать set -iи set +iвключать и выключать эту функцию там, где мне было нужно, но это не работает .
stefanmaric
источник
2

Ни один из других методов не работал для меня [ source /path/to/filevs . ./path/to/file, alias и т. Д.], Пока, благодаря этому руководству, я не обнаружил, что с помощью:

#!/usr/bin/env bash притон

вместо более простого #!/usr/bin/envможно передавать аргументы интерпретатору, который, я думаю, является ключевым здесь - см. этот документ для получения дополнительной информации.

В любом случае, если исходные команды в любой форме не работают для вас, попробуйте проверить свой шебанг, это может быть проблемой :)

Nikksno
источник