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
, obvyklershd
, nebo bezpečný shell démonsshd
. 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 jakosh
.--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
anirshd
anisshd
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ů).
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 (jakofortune
,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 meziscp2
/sftp
asftp-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 naread(2)
. Mezitím, po zpracování profilu
shellu na vzdálené straně,scp
v režimu dřezu,
který také blokujeread(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
.