Login skripte — šta se izvršava pri prijavi na sistem
Alias radi u terminalu, ali ne radi u skripti. Komanda se izvršava kad je kucaš rukom, a u cronu javlja da ne postoji. Podesio si promenljivu, a preko SSH-a je nema.
Sve tri situacije imaju isti uzrok: bash ne čita uvek iste fajlove. Koje će pročitati, zavisi od toga kako je pokrenut. Ova stranica objašnjava taj redosled — a kad ga jednom razumeš, sve tri zagonetke nestaju.
Dve podele koje sve određuju
Bash se pokreće u jednoj od četiri kombinacije, po dva pitanja:
Da li je login shell? Jeste kad se prijaviš na sistem — preko SSH-a,
na konzoli, ili sa su -. Nije kad otvoriš novi prozor terminala
u već pokrenutoj grafičkoj sesiji.
Da li je interaktivan? Jeste kad ti daje prompt i čeka da kucaš. Nije kad izvršava skriptu.
Proveri gde si trenutno:
$ shopt -q login_shell && echo "login" || echo "nije login" nije login $ echo $- himBHs
Slovo i u drugom ispisu znači interaktivan. Ako ga nema, nije.
Redosled izvršavanja
Login shell (SSH, konzola, su -)
1. /etc/profile
2. /etc/profile.d/*.sh (poziva ih /etc/profile)
3. prvi koji postoji od:
~/.bash_profile
~/.bash_login
~/.profile
Treća stavka je najvažnija zamka: čita se samo prvi pronađeni. Ako
imaš i .bash_profile i .profile, drugi se nikada ne
izvršava. Ljudi izgube sate podešavajući fajl koji sistem uopšte ne gleda.
Interaktivan, ali ne login (novi prozor terminala)
1. /etc/bash.bashrc (na Debian i Ubuntu sistemima) 2. ~/.bashrc
Obrati pažnju: /etc/profile se ovde ne čita. Zato
promenljiva podešena samo tamo ne postoji u novom prozoru terminala.
Neinteraktivan (skripta, cron)
Ništa — osim ako je postavljena promenljiva BASH_ENV
Ovo je odgovor na pitanje zašto cron
posao ne vidi tvoja podešavanja. Skripta pokrenuta iz crona ne čita ni
.bashrc ni .bash_profile.
Odjava
~/.bash_logout (samo pri izlasku iz login shell-a)
Zašto skoro svaki .bash_profile ima ovaj blok
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
Bez njega bi SSH sesija čitala .bash_profile, ali ne i
.bashrc — pa aliasi ne bi radili. Sa njim se čitaju oba, u svakoj
situaciji.
Otud i praktična podela koje se vredi držati:
~/.bash_profile |
Stvari koje se rade jednom po prijavi: promenljive okruženja, PATH, pokretanje agenta za ključeve. |
~/.bashrc |
Stvari koje trebaju svakom shell-u: aliasi, funkcije, izgled prompta, podešavanja istorije. |
Razlog za podelu: promenljive se nasleđuju u potprocesima, pa ih nema smisla postavljati iznova. Aliasi se ne nasleđuju, pa moraju svaki put.
Sistemski fajlovi
/etc/profile.d/ — pravo mesto za izmene
$ ls /etc/profile.d/ bash_completion.sh locale.sh vte.sh Z97-byobu.sh
Kad podešavaš nešto za sve korisnike, ne diraj
/etc/profile — nadogradnja sistema ga može prepisati. Umesto toga
dodaj sopstveni fajl:
$ sudo tee /etc/profile.d/firma.sh > /dev/null << 'EOF' export JAVA_HOME=/opt/java export PATH="$PATH:/opt/firma/bin" EOF
Ostaje netaknut pri nadogradnjama, a lako se ukloni. Nastavak
.sh je obavezan — fajlovi bez njega se ignorišu.
/etc/environment — nije skripta
$ cat /etc/environment PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" LANG=sr_RS.UTF-8
Ovaj fajl čita PAM, ne bash, i to pre svega ostalog. Zbog toga u njemu:
- nema reči
export - nema proširivanja promenljivih —
PATH="$PATH:/opt/bin"ovde ne radi, upisaće se doslovno - nema uslova, petlji ni bilo kakve logike
Prednost je što važi i za grafičke aplikacije i za servise, ne samo za shell.
/etc/skel — šabloni za nove korisnike
$ ls -a /etc/skel . .. .bash_logout .bashrc .profile
Sadržaj se kopira u kućni direktorijum svakog novog naloga. Ako želiš da svi budući korisnici dobiju određeni alias, dodaj ga ovde. Detaljnije na stranici /etc/skel, a podešavanja pri kreiranju naloga na stranici /etc/login.defs.
Kako otkriti šta se zapravo izvršava
Ubaci privremeni ispis u svaki fajl:
$ echo 'echo "--- procitan .bash_profile"' >> ~/.bash_profile $ echo 'echo "--- procitan .bashrc"' >> ~/.bashrc $ echo 'echo "--- procitan .profile"' >> ~/.profile
Zatim isprobaj različite situacije:
$ bash -l -c exit --- procitan .bash_profile --- procitan .bashrc $ bash -i -c exit --- procitan .bashrc $ bash -c exit $
Poslednji red je prazan — neinteraktivna skripta ne čita ništa. Kad završiš, obriši te redove.
Isto proverava i preko SSH-a:
$ ssh server # login, interaktivan $ ssh server 'echo test' # ni login ni interaktivan
Druga komanda ne čita nijedan od tvojih fajlova. Zato skripte koje se pokreću ovako moraju koristiti apsolutne putanje — što je i tema lekcije Apsolutne i relativne putanje.
Tri greške koje se skupo plaćaju
1. Interaktivna komanda u .bashrc
Ovo izgleda bezopasno:
# ~/.bashrc echo "Dobrodosao, $USER!" fortune
A onda:
$ scp fajl.txt server:/tmp/ protocol error: unexpected <newline>
scp, sftp i
rsync očekuju čist protokol na tom kanalu.
Svaki tvoj ispis im pokvari razgovor. Isto važi i za
git push preko SSH-a.
Rešenje je provera interaktivnosti na vrhu .bashrc:
case $- in
*i*) ;;
*) return;;
esac
Ako shell nije interaktivan, fajl se prekida odmah. Većina distribucija
ovaj blok već ima na vrhu .bashrc — nemoj ga uklanjati, i sve
svoje dodaj ispod njega.
2. exit u login skripti
# ~/.bash_profile
if [ -z "$DISPLAY" ]; then
exit
fi
Ovo te zaključava sa sistema. Prijaviš se, skripta se izvrši, sesija se odmah zatvori — i to preko SSH-a, na konzoli, svuda.
Zato pri svakoj izmeni ovih fajlova drži otvorenu drugu sesiju. Postojeća sesija nastavlja da radi; kroz nju popravljaš grešku. Ako druge sesije nema, spas je prijava sa drugim shell-om:
$ ssh -t server /bin/sh
3. Greška u sintaksi
$ ssh server bash: /home/alen/.bashrc: line 42: syntax error near unexpected token `fi'
Sesija radi, ali su podešavanja od tog reda naniže preskočena. Uvek proveri pre nego što se osloniš:
$ bash -n ~/.bashrc $ echo $? 0
Opcija -n proverava sintaksu bez izvršavanja. Isti pristup kao
nginx -t pre restarta servisa, o čemu piše na stranici
Tekstualni editori.
Primena izmena bez odjave
$ source ~/.bashrc $ . ~/.bashrc
Oba oblika rade isto — tačka je prenosiva na sve shell-ove, a
source je čitljiviji.
Razlika koju treba razumeti:
$ ./skripta.sh # potproces, izmene ostaju u njemu $ source skripta.sh # tekući shell, izmene ostaju kod tebe
Zato pokretanje ./podesi.sh ne menja tvoje okruženje, a
source podesi.sh menja. Ovo je uzrok mnogih „skripta je radila,
ali se ništa nije promenilo" situacija.
Posebni slučajevi
su sa crticom i bez nje
$ su marko # zadržava tvoje okruženje, čita samo .bashrc $ su - marko # puna prijava, čita profile fajlove
Druga varijanta je gotovo uvek ono što želiš — inače korisnik dobija tuđi
PATH i tuđe promenljive. Detaljnije na stranici
su.
Isto važi i za sudo:
$ sudo komanda # čisto okruženje, po pravilima u sudoers $ sudo -i # kao da si se root prijavio
Grafičko okruženje
Prijava kroz grafički menadžer ne pokreće bash kao login shell na isti
način. Zato promenljiva podešena u .bash_profile često ne postoji
u aplikacijama pokrenutim iz menija. Za takva podešavanja koristi
/etc/environment ili ~/.config/environment.d/.
Nije bash
$ echo $SHELL /usr/bin/zsh
Ako ti je podrazumevani shell zsh, ništa od gore navedenog ne važi — tamo
su .zshrc i .zprofile. Koji ti je shell dodeljen,
piše u /etc/passwd, u poslednjoj
koloni.
tmux i screen
tmux podrazumevano pokreće login shell u svakom novom prozoru, pa se
profile fajlovi čitaju iznova. To je i razlog zašto se PATH
unutar tmux-a ponekad razlikuje — ako mu se nešto dodaje bez provere, uz svaki
prozor se ponovi. Više o tmux-u na stranici
screen i tmux.
Kratka referenca
Redosled
- Login:
/etc/profile→/etc/profile.d/*.sh→ prvi od~/.bash_profile,~/.bash_login,~/.profile - Interaktivan, ne login:
/etc/bash.bashrc→~/.bashrc - Skripta: ništa (osim
BASH_ENV) - Odjava:
~/.bash_logout
Šta gde ide
~/.bash_profile— promenljive,PATH, jednokratne radnje~/.bashrc— aliasi, funkcije, prompt/etc/profile.d/ime.sh— sistemski, otporno na nadogradnje/etc/environment— bezexport, bez logike, važi i van shell-a
Alati
shopt -q login_shell— da li je login shellecho $-— slovoiznači interaktivanbash -n fajl— provera sintaksesource ~/.bashrc— primeni bez odjavebash -l -c exit,bash -i -c exit— test redosleda
Vežba
Prvo otvori drugu sesiju i ostavi je otvorenom.
- Ubaci prepoznatljiv ispis u sva tri korisnička fajla i utvrdi koji se čitaju pri SSH prijavi, a koji pri otvaranju novog prozora terminala.
- Napravi alias u
~/.bash_profileumesto u~/.bashrc, pa objasni sebi zašto ne radi u novom prozoru. - Postavi promenljivu u
~/.bashrci proveri da li je vidi komanda pokrenuta sassh localhost 'echo $PROMENLJIVA'. - Dodaj sistemsko podešavanje kroz
/etc/profile.d/i proveri da ga vidi i drugi korisnik. - Napravi namernu grešku u sintaksi u
~/.bashrc, otvori novu sesiju da vidiš poruku, pa je popravi iz sesije koju si ostavio otvorenom.
Peti zadatak je vežba navike, ne komande.
Korisnički nalozi i njihova podrazumevana podešavanja su na stranicama /etc/passwd, /etc/skel i /etc/login.defs, a sopstvene prečice na stranici alias.
Cela lekcija je deo vodiča Linux osnove.
Comments
Post a Comment