Prostředí a konfigurace

env proměnné, PATH, .bashrc, dotfiles.

Co se naučíš: Pochopíš PATH a proměnné prostředí a přestaneš řešit, proč příkaz funguje v jednom terminálu a v druhém ne.

16 min čtení + cvičeníNavazuje na:⌨️ Terminál a shell

Každý běžící program potřebuje vědět pár věcí o svém okolí, kdo jsi, kde máš domovský adresář, jaký jazyk používáš, kde má hledat příkazy. Tyhle informace nese prostředí (environment): sada pojmenovaných hodnot, tzv. proměnných prostředí, které shell předává každému programu, co spustíš. Když je pochopíš, přestaneš „přepisovat kód" kvůli každé maličkosti, spoustu chování naladíš zvenku, jen změnou proměnné nebo řádku v konfiguračním souboru.


Pár pojmů na úvod

  • Proměnná prostředí (env variable) = pojmenovaná hodnota (JMÉNO=hodnota), kterou shell drží v paměti a předává programům, které spustí. Např. HOME=/home/ty, LANG=cs_CZ.UTF-8.
  • Konfigurace bez přepisování kódu = program čte nastavení z prostředí nebo souboru, takže stejný binárku naladíš pro různé stroje/uživatele bez zásahu do zdrojáku. Základ přenositelnosti.
  • Shell proměnná vs env proměnná = obyčejná proměnná žije jen v tvém shellu; teprve export z ní udělá env proměnnou, kterou zdědí i podprocesy (viz níže, tohle je nejčastější zádrhel).
  • Konfigurační soubor shellu (dotfile) = skrytý soubor (.bashrc, .profile…) ve tvém domově, který se spustí při startu shellu a nastaví ti prostředí, aliasy a funkce.
  • PATH = seznam složek, kde shell hledá spustitelné příkazy. Bez něj bys musel psát celou cestu ke každému programu. Nejdůležitější proměnná, kterou budeš potkávat pořád.

Co jsou proměnné prostředí a k čemu

Prostředí si představ jako tabulku KLÍČ=HODNOTA, kterou nese každý proces. Když spustíš program, dostane kopii téhle tabulky a může z ní číst. Díky tomu ví editor, kdo jsi (USER), instalátor, kam zapisovat dočasné soubory (TMPDIR), a aplikace, jakým jazykem s tebou mluvit (LANG).

Celou tabulku svého shellu vypíšeš takhle:

env          # vypíše všechny proměnné prostředí
printenv     # to samé (printenv PATH vypíše jen jednu)

Jednu konkrétní proměnnou přečteš přes $:

echo $HOME          # /home/ty
echo $USER          # ty
printenv PATH       # bezpečnější u proměnných, kde by $ mohl něco rozbít

💡 $JMÉNO shell nahradí hodnotou ještě předtím, než příkaz spustí. echo $HOME tedy shell nejdřív přepíše na echo /home/ty a teprve to spustí. Tomuhle se říká expanze proměnné.


Vytvoření proměnné a proč export

Proměnnou vyrobíš prostým přiřazením (žádné mezery kolem =!):

NAZEV=Siti          # správně
NAZEV = Siti        # ŠPATNĚ: shell to bere jako příkaz "NAZEV" s argumenty

Jenže takhle vytvořená proměnná žije jen ve tvém shellu. Podproces (skript, program) ji neuvidí. Aby ji zdědily i procesy, které spustíš, musíš ji exportovat:

export NAZEV=Siti           # vytvoří a rovnou exportuje
# nebo dvoufázově:
NAZEV=Siti
export NAZEV                # zveřejní už existující proměnnou

Rozdíl na příkladu, spustíme podproces (nový bash) a zkusíme proměnnou přečíst:

POKUS=ahoj
bash -c 'echo "podproces vidí: $POKUS"'   # podproces vidí: (prázdné!)

export POKUS
bash -c 'echo "podproces vidí: $POKUS"'   # podproces vidí: ahoj

💡 Proč to tak je: podproces dostává kopii prostředí rodiče a v prostředí jsou jen exportované proměnné. Neexportovaná proměnná zůstává „soukromá" v rodičovském shellu. Proto skoro všechno, co má vidět nějaký program, exportuješ.

Proměnnou zrušíš přes unset NAZEV.


Důležité proměnné, které musíš znát

  • PATH: seznam složek oddělených dvojtečkou, kde shell hledá příkazy (viz vlastní sekce níže).
  • HOME: tvůj domovský adresář (/home/ty). Sem míří cd bez argumentu i zkratka ~.
  • USER: přihlašovací jméno (ty). Programy podle něj poznají, kdo je spustil.
  • SHELL: cesta k tvému výchozímu shellu (/bin/bash). Pozor: říká, jaký shell máš nastavený v systému, ne nutně ten, ve kterém právě píšeš.
  • LANG / LC_*, jazyk a formát (cs_CZ.UTF-8). Ovlivňuje jazyk hlášek, řazení, desetinnou čárku vs tečku, formát data.
  • EDITOR: který editor mají programy otevřít, když tě chtějí nechat něco napsat (git commit, crontab -e…). Např. export EDITOR=nano.
echo "$HOME $USER $SHELL $LANG"
printenv EDITOR

PATH, jak shell hledá příkazy

Když napíšeš ls, shell nezná předem, kde ls leží. Projde postupně složky v PATH (zleva doprava) a spustí první ls, který najde. Podívej se, jak PATH vypadá:

echo $PATH
# /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/home/ty/.local/bin

Jsou to složky oddělené dvojtečkou. Kterou konkrétně shell použil, zjistíš přes which nebo type:

which ls        # /usr/bin/ls
type ls         # ls is /usr/bin/ls

Pokud si chceš přidat vlastní složku s programy (třeba ~/bin), přidáš ji k existujícímu PATH, ne místo něj:

export PATH="$HOME/bin:$PATH"     # svoje bin dej dopředu: má přednost
export PATH="$PATH:$HOME/bin"     # nebo dozadu: použije se jen když nic dřív nesedí

🚩 Všimni si $PATH v hodnotě, tím říkáš „vezmi, co tam bylo, a přidej". Kdybys napsal jen export PATH="$HOME/bin", zahodíš všechny systémové cesty a přestanou fungovat i ls nebo cat. O tomhle průšvihu je celá jedna sekce ve Failure modes.

Aby ti přidání do PATH vydrželo i po zavření terminálu, patří ten export řádek do .bashrc (nebo .profile), viz další sekce.


Konfigurační soubory shellu, .bashrc vs .profile

Když spustíš bash, přečte při startu jeden nebo víc souborů ve tvém domově a provede, co v nich je. Které přesně, závisí na typu shellu:

  • Login shell (přihlášení do textové konzole, ssh, přepnutí přes su -) čte ~/.bash_profile (a když neexistuje, ~/.profile). Sem patří věci, které se mají nastavit jednou při přihlášení, hlavně export proměnných jako PATH, EDITOR, LANG.
  • Interaktivní ne-login shell (nový záložka/okno terminálu v grafickém prostředí) čte ~/.bashrc. Sem patří věci pro každodenní psaní, aliasy, funkce, prompt, doplňování.

Aby ses nemusel starat, který zrovna běží, je běžný trik nechat .bash_profile načíst .bashrc:

# ~/.bash_profile
if [ -f ~/.bashrc ]; then
  . ~/.bashrc
fi

Tím máš jedno místo (.bashrc) pro skoro všechno a .bash_profile ho jen „přizve".

💡 Jak poznat, který mám? echo $0 v login shellu vypíše -bash (pomlčka napřed), v běžném okně jen bash. Nemusíš to řešit denně, stačí vědět, že to jsou dva různé případy.


⚠️ Po editaci .bashrc musíš reloadnout

Nejčastější zklamání začátečníka: upravím .bashrc, přidám alias a nic. Důvod: .bashrc se čte jen při startu shellu. Tvůj už běžící terminál o změně neví. Máš dvě možnosti:

source ~/.bashrc     # načte soubor do aktuálního shellu (tečka: . ~/.bashrc dělá totéž)

nebo prostě zavři terminál a otevři nový, ten si .bashrc přečte čerstvě.

🚩 source (nebo .) spustí soubor v aktuálním shellu, takže se změny projeví tady a teď. Kdybys .bashrc spustil jako obyčejný skript (bash ~/.bashrc), proběhne v podprocesu a jakmile skončí, je všechno pryč, v tvém shellu se nezmění nic.


Aliasy a funkce, zkratky, které si nastavíš

Alias je přezdívka pro delší příkaz. Napíšeš krátké, shell to nahradí dlouhým:

alias ll='ls -la'                 # ll = detailní výpis včetně skrytých
alias ..='cd ..'
alias grep='grep --color=auto'    # obarví shody

Když potřebuješ víc než jen náhradu textu (argumenty, víc příkazů, logiku), použij funkci:

# vytvoř složku a rovnou do ní vejdi
mkcd() {
  mkdir -p "$1" && cd "$1"
}

Obojí patří do .bashrc, aby ti to vydrželo. Po přidání nezapomeň na source ~/.bashrc:

# ~/.bashrc
alias ll='ls -la'
alias gs='git status'

mkcd() { mkdir -p "$1" && cd "$1"; }

💡 Aktuálně platné aliasy vypíšeš příkazem alias (bez argumentů). Jeden zrušíš unalias ll.


Dotfiles a jejich verzování (krátce)

.bashrc, .profile, .gitconfig, .vimrc a spol. se souhrnně říká dotfiles, jsou skryté (začínají tečkou) a nesou tvoje osobní nastavení. Protože je to obyčejný text, dá se verzovat gitem: založíš si repozitář (třeba ~/dotfiles), soubory tam dáš a symlinkuješ zpět do domova. Výhoda: na novém stroji máš za minutu úplně stejné prostředí a historii změn máš v gitu.

🚩 Pozor: do veřejného repozitáře dotfiles nikdy nedávej tajemství, tokeny, hesla, SSH klíče. Ta patří jinam (viz Failure modes). Verzuj konfiguraci, ne přihlašovací údaje.


Failure modes, časté omyly začátečníků

  • „Upravil jsem .bashrc a nic se nestalo." Chybí reload. .bashrc se čte jen při startu shellu, spusť source ~/.bashrc nebo otevři nový terminál. Bez toho pořád běžíš na starém prostředí.
  • Přepsání PATH místo přidání. PATH=/opt/bin (bez :$PATH) zahodí všechny systémové cesty a najednou nefunguje ani ls. Vždycky přidávej: PATH="/opt/bin:$PATH". Když se to stane, zavři a otevři nový terminál (nový shell si načte čistý PATH) a řádek oprav.
  • Zapomenutý export. NAZEV=hodnota bez export vidí jen tvůj shell; spuštěný skript/program proměnnou nedostane a chová se, jako by nebyla. Co má vidět podproces, musí být exportované.
  • Mezery kolem =. NAZEV = hodnota není přiřazení, shell to čte jako příkaz NAZEV. Píše se NAZEV=hodnota bez mezer.
  • Tajemství v env nebo v gitnutých dotfiles. Heslo v export DB_PASSWORD=... v .bashrc, který je ve veřejném repu, je únik. Env proměnné navíc vidí i podprocesy a bývají v logách. Citlivé věci drž mimo git (.env v .gitignore, správce hesel, ~/.netrc s právy 600).

🛠️ Cvičení

  1. Prozkoumej svoje prostředí. Vypiš všechny proměnné prostředí a najdi mezi nimi HOME, USER, SHELL a LANG. Pak vypiš jen PATH a spočítej, kolik složek obsahuje (nápověda: oddělovač je :).
  2. Export vs neexport. Vytvoř proměnnou TEST=ahoj bez exportu a zkus ji přečíst v podprocesu (bash -c 'echo $TEST'). Pak ji exportuj a zkus znovu. Vysvětli rozdíl.
  3. Přidej si složku do PATH, bezpečně. Vytvoř ~/bin, dej do ní jednoduchý spustitelný skript a přidej ~/bin do PATH tak, aby ses ke skriptu dostal pouhým jménem. Proč musí být v hodnotě $PATH?
  4. Alias a funkce, které přežijí restart. Přidej do .bashrc alias ll='ls -la' a funkci mkcd. Ověř, že po source ~/.bashrc fungují. Co by se stalo, kdybys source vynechal?
  5. .bashrc vs .profile. Zjisti, který z těchto souborů máš v domově, a rozhodni, kam patří export EDITOR=nano a kam alias gs='git status'. Zdůvodni.
Náčrt řešení: rozbal, až si cvičení zkusíš sám
  1. Prostředí, env (nebo printenv) vypíše vše; konkrétní najdeš třeba printenv HOME USER SHELL LANG. Jen cestu: echo $PATH. Počet složek napůl ručně, nebo echo $PATH | tr ':' '\n' | wc -l. Pozor: PATH je jedna proměnná, uvnitř seznam oddělený dvojtečkami, ne víc proměnných.
  2. Export vs neexport, TEST=ahoj; bash -c 'echo $TEST' vypíše prázdno, protože podproces dostává jen exportované proměnné. Po export TEST už bash -c 'echo $TEST' vypíše ahoj. Rozdíl: neexportovaná proměnná zůstává soukromá v rodičovském shellu; export ji vloží do prostředí, které se dědí do podprocesů. Pozor: export platí i pro všechny další spuštěné programy, ne jen ten jeden.
  3. Vlastní PATH, mkdir -p ~/bin, do ~/bin/pozdrav dáš skript, chmod +x ~/bin/pozdrav, pak export PATH="$HOME/bin:$PATH". Teď stačí napsat pozdrav. V hodnotě musí být $PATH, protože jinak bys všechny původní cesty zahodil a rozbil běžné příkazy, $PATH znamená připoj to k tomu, co tam bylo. Aby to vydrželo, dej ten řádek do .bashrc. Pozor: pořadí rozhoduje, složka vlevo má přednost.
  4. Alias a funkce, do .bashrc přidáš alias ll='ls -la' a mkcd() { mkdir -p "$1" && cd "$1"; }, pak source ~/.bashrc. Bez source (a bez nového terminálu) se změny neprojeví, protože .bashrc se čte jen při startu shellu, tvůj běžící shell o úpravě neví. Pozor: source běží v aktuálním shellu; bash ~/.bashrc by proběhl v podprocesu a nic by ti nezůstalo.
  5. .bashrc vs .profile, export EDITOR=nano (a obecně export proměnných jako PATH, LANG) patří do .profile/.bash_profile, protože se nastavuje jednou při přihlášení a dědí se dál. Alias gs='git status' patří do .bashrc, protože aliasy platí jen v interaktivním shellu a chceš je v každém novém okně. Běžný trik: .bash_profile načte .bashrc (. ~/.bashrc), ať máš jedno místo. Pozor: aliasy v .profile se ti v grafickém terminálu nemusí projevit, proto patří do .bashrc.

🧠 Otázky & odpovědi

K čemu jsou proměnné prostředí a proč jsou lepší než měnit kód?

Proměnná prostředí je pojmenovaná hodnota (třeba HOME nebo LANG), kterou shell drží v paměti a předává každému programu, co spustíš. Program si z ní přečte, jak se má chovat, kdo jsi, jaký jazyk používáš, kde má hledat příkazy. Výhoda oproti přepisování zdrojáku je obrovská: stejnou binárku nebo skript naladíš pro jiný stroj, jiného uživatele nebo jiné prostředí (test vs produkce) jen změnou proměnné, bez zásahu do kódu a bez nového buildu. Proto se přes prostředí předávají třeba přístupové údaje, cesty a přepínače chování.

Proč musím proměnnou exportovat a co se stane, když to neudělám?

Obyčejné přiřazení (NAZEV=hodnota) vytvoří proměnnou, která žije jen v tvém aktuálním shellu. Podproces, spuštěný skript nebo program, dostává jen kopii prostředí, a v tom prostředí jsou pouze exportované proměnné. Bez exportu ji tedy podproces neuvidí a chová se, jako by neexistovala. Jakmile napíšeš export NAZEV, proměnná se vloží do prostředí a zdědí ji každý proces, který od té chvíle spustíš. Proto skoro všechno, co má vidět nějaký program (PATH, EDITOR, přístupové tokeny), exportuješ.

Jak funguje PATH a proč ho nesmím přepsat?

PATH je seznam složek oddělených dvojtečkou, ve kterých shell hledá spustitelné příkazy. Když napíšeš ls, shell projde ty složky zleva doprava a spustí první ls, na který narazí, proto nemusíš psát celou cestu. Když si přidáváš vlastní složku, musíš připojit k tomu, co tam už je: PATH=$HOME/bin:$PATH. Kdybys napsal jen PATH=$HOME/bin, zahodíš všechny systémové cesty a přestanou fungovat i základní příkazy jako ls nebo cat, protože je shell najednou nemá kde najít. Když se ti to povede, stačí zavřít a otevřít nový terminál, ten si načte čistý PATH a řádek opravit.

Jaký je rozdíl mezi .bashrc a .bash_profile a kdy se čtou?

Záleží na typu shellu. Login shell (přihlášení do konzole, ssh, su -) čte .bash_profile, a když neexistuje, .profile, sem patří věci nastavené jednou při přihlášení, hlavně export proměnných jako PATH nebo EDITOR. Interaktivní ne-login shell (nové okno terminálu v grafice) čte .bashrc, sem patří aliasy, funkce a nastavení promptu, tedy věci pro každodenní psaní. Aby ses tím nemusel trápit, bývá zvykem nechat .bash_profile načíst .bashrc, takže máš jedno místo pro skoro všechno. Když si nejsi jistý, který běží, echo $0 v login shellu ukáže -bash s pomlčkou napřed.

Upravil jsem .bashrc a nic se nezměnilo, co dělám špatně?

Nic zásadního, jen ti chybí reload. Soubor .bashrc se čte pouze při startu shellu, takže tvůj už běžící terminál o úpravě neví. Máš dvě cesty: buď spustit source ~/.bashrc (tečka . ~/.bashrc dělá totéž), což soubor načte přímo do aktuálního shellu a změny se projeví hned, nebo prostě zavřít terminál a otevřít nový, který si .bashrc přečte čerstvě. Pozor na to, že spuštění jako obyčejný skript (bash ~/.bashrc) nepomůže, proběhne v podprocesu a jakmile skončí, je všechno pryč, protože se to nezapsalo do tvého shellu.