Bashrc neden mevcut kabuğun etkileşimli olup olmadığını kontrol ediyor?


62

Benim Arch üzerinde yükleme /etc/bash.bashrcve /etc/skel/.bashrcşu satırları içerir:

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

Debian'da /etc/bash.bashrc:

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

Ve /etc/skel/.bashrc:

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

Göre man bash, ancak, etkileşimli olmayan kabuklar bile bu dosyaları okumaz:

   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.

Doğru anlarsam, *.bashrcdosyalar yalnızca BASH_ENVonlara işaret edecek şekilde ayarlanmışsa okunur . Bu, tesadüfen gerçekleşemeyecek bir şeydir ve yalnızca birisi açıkça değişkeni buna göre ayarladıysa gerçekleşecektir.

Bu, komut dosyalarının, kullanıcının işe yarayabileceği bir şey .bashrcayarlayarak otomatik olarak kaynak yapma olasılığını kırıyor gibi görünüyor BASH_ENV. Açıkça söylenmediği sürece, bash etkileşimli olarak çalıştırılmadığında bu dosyaları hiçbir zaman okumazsa, varsayılan *bashrcdosyalar neden izin vermiyor?


Yanıtlar:


69

Bu, birkaç hafta önce buraya göndereceğim bir soru. Terdon gibi, a'nın.bashrc yalnızca etkileşimli Bash mermileri için kaynaklandığını anladım, bu yüzden .bashrcetkileşimli bir kabukta çalışıp çalışmadığını kontrol etmenin gereği yoktu . Kafa karıştırıcı bir şekilde, kullandığım tüm dağıtımların (Ubuntu, RHEL ve Cygwin) , mevcut kabuğun etkileşimli olmasını sağlamak için bir tür kontrol (test $-veya $PS1) yapıldı. Kargo kültü programlamasını sevmiyorum, bu yüzden bu kodun amacını anlamaya karar verdim .bashrc.

Bash'in uzak mermiler için özel bir durumu var

Sorunu araştırdıktan sonra, uzak mermilere farklı şekilde davranıldığını keşfettim . Etkileşimli olmayan Bash kabukları normalde ~/.bashrcbaşlangıçta komut çalıştırmazken , kabuk uzak kabuk arka plan programı tarafından çağrıldığında özel bir durum ortaya çıkar :

Bash, genellikle uzaktaki kabuk cini rshdveya genellikle güvenli kabuk cini tarafından çalıştırıldığı gibi bir ağ bağlantısına bağlı standart girişi ile ne zaman çalıştırıldığını belirlemeye çalışır sshd. Bash'in bu şekilde çalıştırıldığını belirlerse, bu dosya varsa ve okunabiliyorsa, ~ / .bashrc komutlarını okur ve yürütür. Olarak çağrıldığında bunu yapmaz sh. --norcSeçeneği bu davranışı engellemek için kullanılabilirler ve --rcfileopsiyon okunacak başka bir dosya zorlamak için kullanılabilir, ancak hiçbiri rshdne de sshdgenel olarak kabuğu bu seçeneklerle çağırmaz veya belirtilen izin verir.

Örnek

Uzaktan kumandanın başına aşağıdakileri yerleştirin .bashrc. (Eğer .bashrctarafından kaynaklanmışsa .profileveya .bash_profiletest sırasında bunu geçici olarak devre dışı bırakın):

echo bashrc
fun()
{
    echo functions work
}

Aşağıdaki komutları yerel olarak çalıştırın:

$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
  • Hiçbir iyer $-kabuğu olduğunu gösterir etkileşimli olmayan .
  • Lider yok -içinde $0kabuk bir olmadığını gösterir giriş kabuğu .

Uzaktan kumandada tanımlanan Shell işlevleri .bashrcde çalıştırılabilir:

$ ssh remote_host fun
bashrc
functions work

Ben fark ~/.bashrcedilir sadece bir komut için argüman olarak belirtildiğinde kaynaklı ssh. Bu mantıklı: sshnormal bir giriş kabuğu başlatmak için kullanıldığında .profileveya .bash_profileçalıştırıldığında (ve .bashrcyalnızca açıkça bu dosyalardan biri tarafından yapıldığında kaynaklanır).

.bashrc(Etkileşimli olmayan) bir uzaktan kumanda komutunu çalıştırırken elde ettiğim en büyük yarar , kabuk işlevlerinin çalıştırılabilmesidir. Bununla birlikte, tipik bir komuttaki komutların .bashrcçoğu yalnızca etkileşimli bir kabuk ile ilgilidir, örneğin kabuk etkileşimli olmadığı sürece diğer adlar genişletilmez.

Uzaktan dosya aktarımı başarısız olabilir

Bu genellikle etkileşimli bir oturum açma kabuğunu başlatmak için rshveya sshkullanıldığında veya etkileşimli olmayan kabukların komutları çalıştırmak için kullanıldığında bir sorun değildir . Ancak, bir sorun olabilir gibi programlar için rcp, scpve sftpkullanan uzaktan kabukları veri aktarımı için.

scpKomut kullanılırken uzak kullanıcının varsayılan kabuğunun (Bash gibi) tam olarak başlatıldığı anlaşılıyor . Man sayfasında bu konuda bir şey yok - sadece veri aktarımı için scpkullanılan bir söz ssh. Bunun sonucu olarak, standart çıktıya basan herhangi bir komut varsa .bashrc, dosya transferlerinin başarısız olacağı , örneğin scp'nin hatasız olarak sonuçlanacağı sonucuna varılmıştır .

Ayrıca, 15 yıl öncesine ait bu Red Hat hata raporuna bakınız , / etc / bashrc'da (nihayetinde kapatılmış WONTFIX) bir yankı komutu varken scp kesiliyor .

Neden scpve sftpbaşarısız

SCP (Güvenli kopya) ve SFTP (Güvenli Dosya Aktarım Protokolü) , aktarılan dosyalar hakkında bilgi alışverişinde bulunmak için yerel ve uzak uçlar için kendi protokollerine sahiptir. Uzak uçtan beklenmeyen herhangi bir metin (yanlış) protokolün bir parçası olarak yorumlanır ve aktarım başarısız olur. Salyangoz Kitabından bir SSS'ye göre

Genellikle ne olur, olsa da, sunucudaki ya sistemdeki ifadeleri veya kullanıcı başına kabuğu başlatma dosyaları (vardır ki .bashrc, .profile, /etc/csh.cshrc, .loginamaçlanan giriş çıkış metin mesajları gibi (insanlar tarafından okunacak, vs.) fortune, echo "Hi there!", vb.).

Bu tür bir kod yalnızca ttystandart girişe ekli olduğunda etkileşimli girişlerde çıktı üretmelidir . Bu testi yapmazsa, bu metin mesajlarını ait olmadıkları yerlere ekler: bu durumda scp2/ sftpve arasındaki protokol akışını kirletir sftp-server.

Kabuk başlangıç ​​dosyalarının tümüyle alakalı olmasının nedeni, sshd kullanıcı adına herhangi bir programı başlatırken kullanıcının kabuğunu kullanmasıdır (eg / bin / sh -c "command" kullanarak). Bu bir Unix geleneğidir ve avantajları vardır:

  • Uzaktan komutlar çalıştırıldığında, kullanıcının olağan ayarları (komut takma adları, ortam değişkenleri, umask vb.) Etkindir.
  • Bir hesabın kabuğunu devre dışı bırakmak için / bin / false olarak ayarlamanın genel uygulaması, sahibinin herhangi bir komutu çalıştırmasını engeller, kimlik doğrulaması yine de bir nedenden dolayı başarılı bir şekilde başarılı olmalıdır.

SCP protokolü ayrıntıları

SCP'nin nasıl çalıştığının ayrıntılarıyla ilgilenenler için, SCP protokolünün nasıl çalıştığını ayrıntılı olarak içeren ve SCP'nin uzaktaki konuşmacı kabuk profilleriyle çalıştırma hakkındaki ayrıntıları içeren ilginç bilgiler buldum. :

Örneğin, bunu uzak sistemdeki kabuk profilinize eklerseniz olabilir:

Eko ""

Neden sadece takılıyor? Yani nasıl bir şekilde geliyor scpyılında kaynağında modu ilk protokol mesajın onay bekler. İkili değilse 0, bunun uzak bir sorun bildirimi olmasını bekler ve yeni satır gelene kadar daha fazla karakterin hata mesajı oluşturmasını bekler. İlk satırdan sonra başka bir yeni satır yazdırmadığınız için, scpyereliniz bir döngüde kalır ve engellenir read(2). Bu scpsırada , uzaktaki kabuk profili işlendikten sonra read(2), veri aktarımının başlangıcını gösteren ikili bir sıfır bekleyen aynı zamanda engelleme yapan lavabo modunda başlatıldı .

Sonuç / TLDR

Tipikteki ifadelerin .bashrcçoğu sadece rshveya ile uzaktan komut çalıştırırken değil, etkileşimli bir kabuk için kullanışlıdır ssh. Bu gibi durumlarda, kabuk değişkenleri, takma adlar ve işlevleri tanımlamak istenmez - veya gibi programları kullanarak dosyaları aktarırken herhangi bir metni standart çıktıya yazdırmak aktif olarak zararlıdır . Geçerli kabuğun etkileşimli olmadığını doğruladıktan sonra çıkma, en güvenli davranıştır .scpsftp.bashrc


güzel makale. ama ben bunu yapmalıyım? .bashrc tarafından check-in yaptım ama hala 0 kodu ile scp çıkmak ve uzak bir kutuya hiçbir şey kopyalamıyorum
ses

@ses Durumunuzu daha ayrıntılı olarak tanımlayabileceğiniz yeni bir soru sormak en iyisidir.
Anthony G - Monica Adalet

16

Kılavuz sayfası , olduğu gibi etkileşimli olmayan uzak mermiler için bashde kaynaklar olduğunu belirtmeyi ihmal ediyor.bashrc

ssh hostname command

http://git.savannah.gnu.org/cgit/bash.git/tree/shell.c#n1010

 COMMAND        EXECUTE BASHRC
 --------------------------------
 bash -c foo        NO
 bash foo           NO
 foo                NO
 rsh machine ls     YES (for rsh, which calls 'bash -c')
 rsh machine foo    YES (for shell started by rsh) NO (for foo!)
 echo ls | bash     NO
 login              NO
 bash               YES

http://git.savannah.gnu.org/cgit/bash.git/tree/shell.c#n1050

          /* If we were run by sshd or we think we were run by rshd, execute
             ~/.bashrc if we are a top-level shell. */
          if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2)
            {
              maybe_execute_file (SYS_BASHRC, 1);
              maybe_execute_file (bashrc_file, 1);

.Bashrc'nizi .bash_profile (veya .profile) adresinizden alıyor musunuz?
glenn jackman,

Evet, ama mesele bu değil. Bir boş .bash_profileaynı davranışı sergilerdi.
Mikel

Bana neyin gösterdiğinden emin değilim. Bunu rsh(hiç kullanmadığım) kaynakları ~/.bashrcmı söylüyorsun ? Ve bu, uzantı olarak, Linux, bashherkesin bir senaryoyu çalıştırmayı denediği durumlarda engeller rshmi? Zaten bir giriş kabuğu olduğundan, ssh serverdokunmamalısınız .bashrc. Sisteminiz ~ / .bashrc` kaynaklarından biri değilse ~/.profile. Ve ssh server commandbunu yapmamalı bile. Kesinlikle benim sistemimde yok.
terdon

2
Hayır. Seni bashkaynağa değil rshkaynağa bağladım. :) Bu yorum sshaynı zamanda çok uzun zaman önce yazılmış. Daha fazla kaynak içeren güncellenmiş cevaba bakınız.
Mikel,

Ah, bu yardımcı, teşekkür ederim. Bunu nasıl test edebilirim? Bir ekleme çalıştı echoen tepesinde /etc/bash.bashrcve ~/.bashrc(etkileşimli kabuk testlerinin önce) ve hedef ile makineye ssh sonra ssh server hostnameve süre hostnameçalıştırıldı, benim yankıları birini görmedim. Bu benim shell_level(her neyse) değil <2mi?
terdon

5

Kurallara göre, .bashrckullanıcının kabuk için özelleştirme yapılandırmasını sakladığı yerdir.

Bu özelleştirme yapılandırması, ortam değişkenleri, takma adlar, süslü komut istemi olabilir. Etkileşimli olmayan bir kabukla, bu kısa şeylerin anlamı yoktur. Dahası, etkileşimli olmayan bir kabuk birçok bağlamda çağrılabilir, bu ortam değişkenlerinin yanlış bir negatif duruma, hatta güvenlik açığına bile yol açabileceğinden emin değilsiniz.

En yakın örnek şöyle bir takma addır:

alias cp='cp -i'

Ardından interaktif olmayan kabuğunuzu sonsuza dek asın.

Bu yüzden, .bashrcsorun yaşamayacağımızdan emin olmak için kontroller en üstte yapılır.


Kabuk etkileşimli olmayan giriş kabuğu olarak adlandırılabildiğinden , açıkça kaynak engellemenin bir *bashrcanlamı yoktur.

Kabuk zaman etkileşimli olmayan giriş kabuğu olarak adlandırılan bu kaynak /etc/profile, daha sonra ilki bulundu kaynak ~/.bash_profile, ~/.bash_loginve ~/.profile:

Bash etkileşimli bir giriş kabuğu olarak veya --login seçeneğiyle etkileşimli olmayan bir kabuk olarak çağrıldığında , önce bu dosya varsa / etc / profile dosyasındaki komutları okur ve yürütür. Bu dosyayı okuduktan sonra, bu sırada ~ / .bash_profile, ~ / .bash_login ve ~ / .profile ifadelerini arar ve var olan ve okunabilen ilk komuttan komutları okur ve yürütür.

Hiçbir şey bu dosyaların kaynak göstermesini engelleyemez .bashrc, bu yüzden içinde kontrol .bashrcyapmak daha güvenlidir ve işleri kolaylaştırır.


Evet bunu biliyorum. Bu yüzden etkileşimli olmayan mermilerin *bashrcdosyaları hiç kaynaklamamasının nedeni budur . Sorum şu: neden çeşitli Linux satıcıları, etkileşimli olmayan mermilerin bu etkileşimli olmayan mermiler tarafından okunmamışsa, bu dosyaları okumasını açıkça engelleme sorununa neden oluyor.
terdon

1
@ terdon: Bir kabuk etkileşimli olmayan giriş kabuğu olarak adlandırılabildiğinden , o zaman kaynak .bash_profileolabilecek bir giriş kabuğu kaynağı olacaktır .bashrc.
cuonglm

Hayır, etkileşimli olmayan kabuklarda okunan tek şey $BASH_ENV. Her ikisi de *profileve *bashrcgöz ardı edilir. Ya da en azından, man sayfasının söylediği bu. Ancak, Mikel’in gösterdiği gibi, man sayfası yalan söylüyor olabilir.
terdon

@ terdon: İçindeki bağlantı ile güncellenmiş cevabımı oku. bash -l -c :Etkileşimli olmayan bir giriş kabuğu çağırmayı denediniz mi ?
cuonglm

Vay. Kesinlikle haklısın. Bu kısmı yaklaşık --login100 kez okudum, ama görünüşe göre, hiç kayıt olmadı. Teşekkürler!
terdon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.