Gdzie powinienem wyeksportować zmienną środowiskową, aby wszystkie kombinacje bash / dash, interaktywne / nieinteraktywne, logowanie / non-login, ją pobrały?

11

Oto motywacja pytania:

Używam Ubuntu 12.04 LTS 2 z pulpitem Unity. W moim pliku .bashrc dołączam kilka katalogów do mojej zmiennej PATH i definiuję kilka zmiennych środowiskowych, takich jak JAVA_HOME. Kiedy uruchamiam aplikacje z terminala (uruchamiając bash, moją domyślną powłokę), działa to świetnie, ale w przypadku kilku skrótów, które używają programu uruchamiającego Unity, uruchamiają aplikacje, które wydają się być zdefiniowane do używania #! / Bin / sh, które jest aliasowany do / bin / dash i nie pobierają zawartości ~ / .bashrc ani ~ / .profile.

Podejrzewam, że mógłbym zmienić wszystkie te skróty na użycie / bin / bash zamiast / bin / sh, aby zmusić go do pobierania zmian .bashrc, ale wydaje się to bardzo hackerskie.

Biorąc pod uwagę, że Ubuntu 12.04 (domyślnie) aliasy / bin / sh do / bin / dash i że moją domyślną powłoką jest / bin / bash, istnieje jedno miejsce, w którym mogę wybrać modyfikację PATH i zdefiniować zmienne środowiskowe, jeśli chcę być obecnym we wszystkich tych okolicznościach:

  1. Ilekroć tworzę powłokę bash bez logowania (używając terminalu w jedności)
  2. Ilekroć tworzę powłokę bash logowania (na przykład logowanie zdalne przez ssh)
  3. Ilekroć korzystam z programu uruchamiającego aplikacje Unity (biorąc pod uwagę, że program uruchamiający używa / bin / sh).
  4. Ilekroć wykonywane jest zadanie crona (biorąc pod uwagę, że SHELL = / bin / sh w / etc / crontab).

Jeśli dobrze rozumiem, domyślam się, że:

  • (1) / (2) i (3) / (4) są różne, ponieważ (1) / (2) to bash, a (3) / (4) to dash.
  • (1) i (2) są różne, ponieważ pliki, które bash decyduje się załadować, różnią się w zależności od tego, czy jest to powłoka logowania.
  • (3) i (4) są różne, ponieważ (3) pojawi się w pewnym momencie po zalogowaniu (i stąd ~ / .profile będzie pozyskiwany przez jeden z jego procesów nadrzędnych, podczas gdy (4) pojawi się w pewnym momencie moment, kiedy ja nie zalogowany, a więc ~ / .profile nie zostały przeczytane.

(Nie zdziwiłbym się, gdyby inne czynniki również miały znaczenie, takie jak to, czy powłoka jest interaktywna, więc prawdopodobnie jest więcej kombinacji, których nawet się nie spodziewałem ... Cieszę się, że moje pytanie "zostało ulepszone " w tym wypadku.)

Spodziewałbym się, że w pewnym momencie ktoś musiał stworzyć jakiś przewodnik, który powie ci, jak / gdzie zmodyfikować zmienne środowiskowe w sposób niezależny od powłoki (lub przynajmniej w sposób zgodny z kreską / bitem) ... po prostu mogę ' Wydaje się, że znajdziesz odpowiednie wyszukiwane hasła, aby znaleźć taki przewodnik.

Rozwiązania lub wskazówki do rozwiązań bardzo mile widziane!

Zaktualizowano:

  • Wyjaśnienie: Jest to domyślny użytkownik Ubuntu utworzony w procesie instalacji 12.04, więc nic szczególnego. To nie mają ~ / .profile (jawnie źródła ~ / .bashrc), a jedynym ~ / .bash * Pliki są obecne .bashrc, .bash_history i .bash_logout ... więc nie nie ma .bash_profile.
  • Nacisk na zakres: nie troszczą się o innych niż domyślnej powłoki interaktywnej (bash) i dowolnego skryptu, który zdarza się używać / bin / sh (synonim kreską) muszle, więc nie ma potrzeby, aby skomplikować to z czymś ekstra dla tcsh / ksh / zsh / itp. wsparcie.
Mickalot
źródło
2
Umieść go w jednym pliku, a następnie pozwól innym źródłom go pobrać.
konsolebox
Według strony podręcznika użytkownika, którą mam tutaj, powinien on czytać $ HOME / .profile dla powłok logowania.
Etan Reisner,
@konsolebox Które pliki rc? AFAICT, dash nie ma pliku rc. I jak powiedziałem, myślnik nie wydaje się pobierać zawartości ~ / .profile.
@EtanReisner Tak, i to jest sedno pytania. Kiedy myślnik nie działa jako powłoka logowania (a zatem ~ / .profile nie jest pozyskiwany), co wtedy?
@Mickalot Czy działasz interaktywnie? Jeśli nie, spróbuj dodać do niego opcję -l.
konsolebox

Odpowiedzi:

9

Wywołanie powłoki jest trochę skomplikowane. Strony podręcznika bash i dash zawierają INVOCATIONsekcje na ten temat.

Podsumowując, mówią (więcej szczegółów na stronie podręcznika, powinieneś ją przeczytać):

When bash is                   | it reads
-------------------------------|----------
login shell                    | /etc/profile and then the first of ~/.bash_profile, ~/.bash_login or ~/.profile that exists.
                               |
interactive non-login shell    | /etc/bash.bashrc then ~/.bashrc
                               |
non-interactive shell          | The contents of $BASH_ENV (if it exists)
                               |
interactive (as "sh")          | The contents of $ENV (if it exists)

-

When dash is                   | it reads
-------------------------------|---------
login shell                    | /etc/profile then .profile
                               |
interactive shell              | The contents of ENV (it it exists, can be set in .profile as well as in initial environment)

Nie wiem od razu o innych pociskach, ponieważ nigdy nie używam żadnej z nich. Najlepszym rozwiązaniem może być ustawienie kilku zmiennych środowiskowych, aby wskazywały na wspólny skrypt lokalizacji i ręczne źródło tego (w stosownych przypadkach) w kilku przypadkach, które nie obejmują.

Etan Reisner
źródło
Niestety, sednem tego problemu jest ten, którego brakuje w tablicy rozdzielczej. Gdy pulpit Unity wywołuje dowolny skrypt, który zaczyna się od #! / Bin / sh, uruchamia (jak zakładam) nieinterakcyjną, nieinteraktywną powłokę kreskową. Więc pytanie brzmi: w jaki sposób mogę zrobić te same zmienne środowiskowe dostępne tam , że są obecne wszędzie w macierzy?
Dobrze. Wyobrażam sobie, że dlatego bash dodał BASH_ENV dla tego automatu. Biorąc pod uwagę, że myślnik nie wydaje się mieć nic, co działałoby w tym gnieździe, nie jestem pewien, czy możesz rozwiązać ten problem bez wpływu na zmianę środowiska aplikacji, która uruchamia myślnik (taki, że myślnik go dziedziczy). Wymagałoby to ustawienia zmiennych środowiskowych w środowisku X, w którym pojawia się komentarz .xsession (rc) @Mickalot. To wciąż pozostawia, jak wskazał, czwarty element pominięty (ale sądzę, że to w rzeczywistości celowe).
Etan Reisner,
Ponieważ jestem na Ubuntu 12.04 LTS, cron jest w rzeczywistości pixie-cron, więc mogę zdefiniować zmienne env w moim pliku crontab ... Zgaduję, że SHELL = / bin / bash i BASH_ENV = ~ / .bashrc powinien to zrobić?
3

Istnieje więc kilka sposobów podejścia do tego. Wiele osób:

za. Posiadaj jeden plik, który ma cechy wspólne dla wszystkich twoich powłok w stylu sh, powiedzmy, .shcommonw każdej .profile .bashrc .kshrcet etetra, po prostu zrób to z. .shcommon

b. Włóż wszystko .profilei zrób to z innych plików.

Rzeczy, które są potrzebne dla określonych powłok lub dla powłok interaktywnych vs. nieinteraktywnych, mogą następnie znaleźć się w odpowiednim pliku przed pozyskiwaniem .shcommon

Osobiście nie lubię zarządzać wieloma plikami. Więc używam następującego podejścia:

Po pierwsze, wszystko, czego potrzebuję, wchodzi w grę .profile Ponieważ mam pewne rzeczy specyficzne dla bash i ksh, określam bieżącą nazwę powłoki, używając:

# get name of current shell
# strip leading - from login shell
export SHELLNAME="${0#-}"

a następnie mają polecenia dla określonych powłok w czymś takim, jak poniżej (niektórzy wolą instrukcję case).

if [ "$SHELLNAME" = 'bash' ]
then
    shopt -s checkwinsize

elif [ "$SHELLNAME" = 'ksh' ]
then
    stty erase ^?
fi

Jeśli mam polecenia, które powinny działać tylko w interaktywnych powłokach, używam następujących poleceń:

# check for interactive flag i in shell options $-
# in bash and ksh you could use the following, but breaks in dash
# if [[ $- == *i* ]]
if [ "$(echo $- | grep i)" != "" ]
then
  fortune
fi

Rzeczy, które są wspólne we wszystkich muszlach typu sh, np. PATHMogą po prostu iść na górę.

Następnie używam dowiązań symbolicznych, aby załadować ten sam plik we wszystkich powłokach typu sh:

ln -s .profile .bashrc
ln -s .profile .kshrc

Kilka uwag dodatkowych, jeśli masz .bash_profile, to bash załaduje to zamiast, .profileale myślnik i ksh nadal się załaduje .profile To może być część twojego problemu.

Możesz też rozważyć użycie #!/bin/bashskryptów zamiast, #!/bin/dashchyba że naprawdę chcesz skryptów zgodnych z POSIX. bash ma wiele dodatkowych funkcji, które są bardzo miłe i wywoływane jest myślnik lub bash, ponieważ sh wyłączy wiele z tych funkcji.

Ponadto, strona podręcznika bash dobrze objaśnia, kiedy ładuje się .profileversus .bashrc. Podobne zasady dotyczą ksh. dash ładuje się .profileprzy logowaniu i pozwala załadować plik przy uruchamianiu interaktywnych powłok, który jest określony przy użyciu ENVzmiennej środowiskowej w .profile(sprawdź stronę podręcznika dash i wyszukaj plik .profile).


źródło
Czy nie możesz po prostu przetestować 0 $ dla nazwy powłoki? Czy istnieją powłoki / przypadki, w których to nie działa?
Etan Reisner,
Podobnie, czy sprawdzanie i w $ - nie wystarcza do interaktywnego testu powłoki? (Będzie wyzwalać powłok interaktywnych bez tty I przyznać jednak, że może lub nie może być niepożądany efekt uboczny.)
Etan Reisnera
@Etan: Hrm, wiem, że najpierw próbowałem $0i miałem problemy ... Nie mogę sobie przypomnieć, jakie dokładnie były. Zalogowaniu się bezpośrednio do konsoli ma pokazać $0jak -bashzamiast bashale które mogą być naprawione.
@Etan: Tak, sprawdzanie, czy ja $-też działa. Musiałbym pomyśleć o tym, kiedy miałbyś interaktywną powłokę bez tty? Twoje rozwiązanie ma z jakiegoś powodu lepsze „wyczucie”. Mogę to zmienić.
-W -bashśrodki „login shell”, ale tak byś należy uwzględnić, że w miejscach, gdzie teście wartość lub chcesz wyświetlić go komuś.
Etan Reisner,
0

Ponieważ przypadki (1) i (2) są rozwiązywane przez pozyskiwanie moich zmiennych środowiskowych w .bashrc i .profile, prawdziwym pytaniem jest „jaka jest nazwa pliku, w którym źródła tych samych zmiennych dla (3) i (4).

Wygląda na to, że istnieje odpowiedź na część (3) pytania (jak uzyskać zmienną środowiskową do zaimportowania na pulpicie Unity) na askubuntu . Sugeruje się utworzenie pliku ~ / .xsessionrc, który będzie pozyskiwany przez / etc / X11 / Xsession. (Próbowałem tego i wydaje się, że działa ... tak!)

Nadal jestem zakłopotany tym, co robić (4). Z pewnością, jeśli mogę utworzyć zadanie cron (lub demona), mogę zastąpić „/ bin / foo” z czymś w rodzaju „bash -c -i / bin / foo”, aby zmusić go do używania bash załadować odpowiednie zmienne środowiskowe, ale oznacza to również, że będę musiał majstrować przy narzędziach innych firm, które mogą instalować zadania demona lub zadanie crona w moim imieniu. Fuj

Mickalot
źródło