GNU/Linux >> Znalost Linux >  >> Linux

Proč Bashrc kontroluje, zda je aktuální shell interaktivní?

Při instalaci Archu /etc/bash.bashrc a /etc/skel/.bashrc obsahovat tyto řádky:

# If not running interactively, don't do anything
[[ $- != *i* ]] && return

V Debianu /etc/bash.bashrc má:

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

A /etc/skel/.bashrc :

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

Podle man bash , nicméně neinteraktivní shelly tyto soubory ani nečtou:

   When  bash  is  started  non-interactively,  to run a shell script, for
   example, it looks for the variable BASH_ENV in the environment, expands
   its  value if it appears there, and uses the expanded value as the name
   of a file to read and execute.  Bash behaves as if the  following  com‐
   mand were executed:
          if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
   but  the value of the PATH variable is not used to search for the file‐
   name.

Pokud tomu dobře rozumím, *.bashrc soubory budou čteny pouze v případě, že BASH_ENV je nastaven tak, aby na ně ukazoval. To je něco, co se nemůže stát náhodou a stane se to pouze v případě, že někdo proměnnou podle toho explicitně nastavil.

Zdá se, že to narušuje možnost, aby skripty byly zdrojem .bashrc uživatele automaticky nastavením BASH_ENV , něco, co by se mohlo hodit. Vzhledem k tomu, že bash tyto soubory při neinteraktivním spuštění nikdy nebude číst, pokud to není výslovně řečeno, proč výchozí *bashrc soubory to zakazují?

Přijatá odpověď:

To je otázka, kterou jsem sem chtěl napsat před pár týdny. Jako terdon , pochopil jsem, že .bashrc pochází pouze pro interaktivní shelly Bash, takže by neměl být potřeba .bashrc zkontrolovat, zda běží v interaktivním prostředí. Je matoucí, že vše distribuce, které používám (Ubuntu, RHEL a Cygwin), měly nějaký typ kontroly (testování $- nebo $PS1 ), abyste zajistili, že aktuální shell bude interaktivní. Nemám rád programování kultu cargo, takže jsem se rozhodl pochopit účel tohoto kódu ve svém .bashrc .

Bash má speciální pouzdro pro vzdálené shelly

Po prozkoumání problému jsem zjistil, že vzdálené shelly se zachází jinak. Zatímco neinteraktivní shelly Bash běžně nespouštějí ~/.bashrc příkazy při spouštění, speciální případ je vytvořen, když je shell vyvolán vzdáleným démonem shellu:

Bash se pokouší určit, kdy je spuštěn se svým standardním vstupem
připojeným k síťovému připojení, jako když je spuštěn vzdáleným démonem shell
, obvykle rshd , nebo bezpečný shell démon sshd . Pokud Bash
určí, že se spouští tímto způsobem, čte a provádí příkazy
z ~/.bashrc, pokud tento soubor existuje a je čitelný. Neudělá to, pokud je
vyvoláno jako sh . --norc k potlačení tohoto chování lze použít volbu
a --rcfile možnost může být použita k vynucení čtení jiného souboru, ale
ani rshd ani sshd obecně vyvolejte shell s těmito možnostmi nebo
povolte jejich specifikaci.

Příklad

Vložte následující na začátek vzdáleného .bashrc . (Pokud .bashrc pochází z .profile nebo .bash_profile , dočasně to během testování deaktivujte):

echo bashrc
fun()
{
    echo functions work
}

Spusťte lokálně následující příkazy:

$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
  • Ne i v $- označuje, že shell je neinteraktivní .
  • Žádný úvodní znak - v $0 označuje, že shell není přihlašovací shell .

Funkce shellu definované ve vzdáleném .bashrc lze také spustit:

$ ssh remote_host fun
bashrc
functions work

Všiml jsem si, že ~/.bashrc je pouze zdroj, když je příkaz zadán jako argument pro ssh . To dává smysl:když ssh se používá ke spuštění běžného přihlašovacího shellu .profile nebo .bash_profile jsou spuštěny (a .bashrc je získáváno pouze tehdy, je-li tak výslovně učiněno jedním z těchto souborů).

Související:Php:current — Vrátí aktuální prvek v poli

Hlavní přínos vidím v tom, že mám .bashrc Zdrojem při spuštění (neinteraktivního) vzdáleného příkazu je, že lze spouštět funkce shellu. Většina příkazů je však v typickém .bashrc jsou relevantní pouze v interaktivním prostředí, např. aliasy se nerozbalí, pokud není prostředí interaktivní.

Vzdálené přenosy souborů mohou selhat

Při rsh to obvykle není problém nebo ssh se používají ke spuštění interaktivního přihlašovacího shellu nebo když se neinteraktivní shelly používají ke spouštění příkazů. Nicméně může to být problém pro programy jako rcp , scp a sftp které používají vzdálené shelly pro přenos dat.

Ukázalo se, že výchozí shell vzdáleného uživatele (jako Bash) je implicitně spuštěn při použití scp příkaz. Na manuálové stránce o tom není žádná zmínka – pouze zmínka o tom, že scp používá ssh pro jeho přenos dat. To má za následek, že pokud je .bashrc obsahuje jakékoli příkazy, které se tisknou na standardní výstup, přenosy souborů se nezdaří , např. scp selže bez chyby.

Proč scp a sftp selhat

SCP (Secure copy) a SFTP (Secure File Transfer Protocol) mají své vlastní protokoly pro místní a vzdálené konce pro výměnu informací o přenášených souborech. Jakýkoli neočekávaný text ze vzdáleného konce je (špatně) interpretován jako součást protokolu a přenos se nezdaří. Podle FAQ z Snail Book

Často se však stává, že na serveru jsou příkazy buď v
spouštěcích souborech systému nebo prostředí pro jednotlivé uživatele (.bashrc , .profile , /etc/csh.cshrc , .login , atd.), které při přihlášení vydávají textové zprávy
určené ke čtení lidmi (jako fortune , echo "Hi there!" , atd.).

Takový kód by měl vytvářet výstup pouze při interaktivních přihlášeních, pokud existuje tty připojený ke standardnímu vstupu. Pokud tento test neprovede,
vloží tyto textové zprávy tam, kam nepatří:v tomto případě znečišťuje
proud protokolu mezi scp2 /sftp a sftp-server .

Důvod, proč jsou spouštěcí soubory shellu vůbec relevantní, je sshd využívá uživatelský shell při spouštění jakýchkoli programů jménem uživatele (pomocí např. /bin/sh -c „příkaz“). Toto je unixová tradice a má
výhody:

  • Při spouštění vzdálených příkazů se uplatní obvyklé nastavení uživatele (aliasy příkazů, proměnné prostředí, umask,
    atd.).
  • Běžná praxe nastavení shellu účtu na /bin/false pro deaktivaci
    zabrání vlastníkovi spouštět jakékoli příkazy, pokud by autentizace
    z nějakého důvodu stále byla náhodně úspěšná.

Podrobnosti protokolu SCP

Pro ty, kdo se zajímají o podrobnosti o tom, jak SCP funguje, jsem našel zajímavou informaci v Jak funguje protokol SCP, který obsahuje podrobnosti o Spuštění scp s upovídanými profily shellu na vzdálené straně? :

To se například může stát, pokud toto přidáte do svého profilu shellu na
vzdáleném systému:

echo “”

Proč jen visí? To pochází ze způsobu scp ve zdroji mode
čeká na potvrzení první protokolové zprávy. Pokud to není binární
0, očekává, že jde o upozornění na vzdálený problém, a čeká, až
další znaky vytvoří chybovou zprávu, dokud nepřijde nový řádek. Protože
jste po prvním nevytiskli další nový řádek, vaše místní scp jen
zůstává ve smyčce a je blokován na read(2) . Mezitím, po zpracování profilu
shellu na vzdálené straně, scp v režimu dřezu,
který také blokuje read(2) , čekající na binární nulu označující začátek
přenosu dat.

Závěr / TLDR

Většina příkazů v typickém .bashrc jsou užitečné pouze pro interaktivní shell – ne při spouštění vzdálených příkazů pomocí rsh nebo ssh . Ve většině takových situací není nastavení proměnných prostředí, aliasů a definování funkcí žádoucí – a tisk jakéhokoli textu standardní výstup je aktivně škodlivý při přenosu souborů pomocí programů jako scp nebo sftp . Ukončení po ověření, že aktuální shell je neinteraktivní, je nejbezpečnější chování pro .bashrc .


Linux
  1. Počítejte v linuxovém shellu s GNU bc

  2. Účel .bashrc a jak to funguje?

  3. Jak zkontrolovat, zda je Shell přihlašovací/interaktivní/dávkový?

  1. Proč potřebuje uživatel root oprávnění sudo?

  2. Pokud procesy zdědí prostředí rodiče, proč potřebujeme export?

  3. Co znamená Ampersand na konci řádku skriptu Shell?

  1. Proč jsou ve výchozím nastavení interaktivní shelly na přihlašovacích shellech Osx?

  2. Proč nikdo nepoužívá The True Bourne Shell jako /bin/sh?

  3. Obnovit .bashrc z aktuálního prostředí?