GNU/Linux >> Belajar Linux >  >> Linux

Mengapa Bashrc Memeriksa Apakah Shell Saat Ini Interaktif?

Pada instalasi Arch saya, /etc/bash.bashrc dan /etc/skel/.bashrc berisi baris berikut:

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

Di Debian, /etc/bash.bashrc memiliki:

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

Dan /etc/skel/.bashrc :

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

Menurut man bash , namun, shell non-interaktif bahkan tidak membaca file ini:

   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.

Jika saya mengerti dengan benar, *.bashrc file hanya akan dibaca jika BASH_ENV diatur untuk menunjuk ke mereka. Ini adalah sesuatu yang tidak bisa terjadi secara kebetulan dan hanya akan terjadi jika seseorang secara eksplisit mengatur variabelnya.

Itu tampaknya mematahkan kemungkinan memiliki skrip sumber .bashrc . pengguna secara otomatis dengan menyetel BASH_ENV , sesuatu yang bisa berguna. Mengingat bash tidak akan pernah membaca file-file ini ketika dijalankan secara non-interaktif kecuali secara eksplisit diperintahkan untuk melakukannya, mengapa default *bashrc file melarangnya?

Jawaban yang Diterima:

Ini adalah pertanyaan yang akan saya posting di sini beberapa minggu yang lalu. Suka terdon , saya mengerti bahwa .bashrc hanya bersumber untuk shell Bash interaktif sehingga tidak perlu .bashrc untuk memeriksa apakah itu berjalan di shell interaktif. Yang membingungkan, semua distribusi yang saya gunakan (Ubuntu, RHEL dan Cygwin) memiliki beberapa jenis pemeriksaan (pengujian $- atau $PS1 ) untuk memastikan shell saat ini interaktif. Saya tidak suka pemrograman kultus kargo jadi saya mulai memahami tujuan kode ini di .bashrc saya .

Bash memiliki wadah khusus untuk cangkang jarak jauh

Setelah meneliti masalah ini, saya menemukan bahwa kerang jarak jauh diperlakukan berbeda. Sementara shell Bash non-interaktif biasanya tidak menjalankan ~/.bashrc perintah saat start-up, kasus khusus dibuat ketika shell Dipanggil oleh daemon shell jarak jauh:

Bash mencoba menentukan kapan dijalankan dengan input standarnya
terhubung ke koneksi jaringan, seperti saat dijalankan oleh daemon shell
jarak jauh, biasanya rshd , atau daemon shell aman sshd . Jika Bash
menentukan sedang dijalankan dengan cara ini, ia membaca dan mengeksekusi perintah
dari ~/.bashrc, jika file itu ada dan dapat dibaca. Itu tidak akan melakukan ini jika
dipanggil sebagai sh . --norc opsi dapat digunakan untuk menghambat perilaku ini,
dan --rcfile opsi dapat digunakan untuk memaksa file lain untuk dibaca, tetapi
tidak ada rshd atau sshd umumnya memanggil shell dengan opsi tersebut atau
mengizinkannya untuk ditentukan.

Contoh

Masukkan yang berikut ini di awal .bashrc jarak jauh . (Jika .bashrc bersumber dari .profile atau .bash_profile , nonaktifkan sementara ini saat menguji):

echo bashrc
fun()
{
    echo functions work
}

Jalankan perintah berikut secara lokal:

$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
  • Tidak ada i di $- menunjukkan bahwa shell non-interaktif .
  • Tidak ada - di depan di $0 menunjukkan bahwa shell bukan login shell .

Fungsi shell didefinisikan dalam .bashrc jarak jauh juga dapat dijalankan:

$ ssh remote_host fun
bashrc
functions work

Saya perhatikan bahwa ~/.bashrc adalah hanya bersumber ketika perintah ditetapkan sebagai argumen untuk ssh . Ini masuk akal:ketika ssh digunakan untuk memulai shell login biasa, .profile atau .bash_profile dijalankan (dan .bashrc hanya bersumber jika dilakukan secara eksplisit oleh salah satu file ini).

Terkait:Php:saat ini — Mengembalikan elemen saat ini dalam array

Manfaat utama yang dapat saya lihat untuk memiliki .bashrc bersumber saat menjalankan perintah jarak jauh (non-interaktif) adalah bahwa fungsi shell dapat dijalankan. Namun, sebagian besar perintah dalam .bashrc yang khas hanya relevan di shell interaktif, mis., alias tidak diperluas kecuali shell interaktif.

Transfer file jarak jauh bisa gagal

Ini biasanya tidak menjadi masalah ketika rsh atau ssh digunakan untuk memulai shell login interaktif atau ketika shell non-interaktif digunakan untuk menjalankan perintah. Namun, itu bisa menjadi masalah untuk program seperti rcp , scp dan sftp yang menggunakan kerang jarak jauh untuk mentransfer data.

Ternyata shell default pengguna jarak jauh (seperti Bash) secara implisit dimulai saat menggunakan scp memerintah. Tidak disebutkan tentang ini di halaman manual – hanya disebutkan bahwa scp menggunakan ssh untuk transfer datanya. Ini memiliki konsekuensi bahwa jika .bashrc berisi perintah apa pun yang mencetak ke output standar, transfer file akan gagal , misalnya, scp gagal tanpa kesalahan.

Mengapa scp dan sftp gagal

SCP (Salinan Aman) dan SFTP (Protokol Transfer File Aman) memiliki protokol sendiri untuk ujung lokal dan jarak jauh untuk bertukar informasi tentang file yang sedang ditransfer. Setiap teks tak terduga dari ujung jarak jauh (salah) ditafsirkan sebagai bagian dari protokol dan transfer gagal. Menurut FAQ dari Buku Siput

Namun, yang sering terjadi adalah bahwa ada pernyataan dalam
sistem atau file startup shell per-pengguna di server (.bashrc , .profile , /etc/csh.cshrc , .login , dll.) yang menampilkan pesan teks saat login,
dimaksudkan untuk dibaca oleh manusia (seperti fortune , echo "Hi there!" , dll.).

Kode tersebut seharusnya hanya menghasilkan output pada login interaktif, ketika ada tty dilampirkan ke input standar. Jika tidak melakukan pengujian ini, ia akan
menyisipkan pesan teks ini di tempat yang bukan tempatnya:dalam hal ini, mencemari
aliran protokol antara scp2 /sftp dan sftp-server .

Alasan file startup shell relevan sama sekali, adalah karena sshd menggunakan cangkang pengguna saat memulai program apa pun atas nama pengguna (menggunakan mis. /bin/sh -c "perintah"). Ini adalah tradisi Unix, dan memiliki
kelebihan:

  • Pengaturan pengguna yang biasa (alias perintah, variabel lingkungan, umask,
    dll.) berlaku saat perintah jarak jauh dijalankan.
  • Praktik umum menyetel shell akun ke /bin/false untuk menonaktifkan
    akan mencegah pemilik menjalankan perintah apa pun, jika autentikasi
    masih berhasil secara tidak sengaja karena suatu alasan.

Detail protokol SCP

Bagi mereka yang tertarik dengan detail cara kerja SCP, saya menemukan informasi menarik di Cara kerja protokol SCP yang mencakup detail tentang Menjalankan scp dengan profil shell yang banyak bicara di sisi jarak jauh? :

Misalnya, ini dapat terjadi jika Anda menambahkan ini ke profil shell Anda di
sistem jarak jauh:

gema “”

Kenapa hanya hang? Itu berasal dari cara scp di sumber mode
menunggu konfirmasi pesan protokol pertama. Jika bukan biner
0, ia mengharapkan pemberitahuan masalah jarak jauh dan menunggu
lebih banyak karakter untuk membentuk pesan kesalahan hingga baris baru tiba. Karena
Anda tidak mencetak baris baru lagi setelah baris pertama, scp lokal Anda hanya
tetap dalam satu lingkaran, diblokir pada read(2) . Sementara itu, setelah profil
shell diproses di sisi jarak jauh, scp dalam mode sink dimulai,
yang juga memblokir read(2) , menunggu nol biner yang menunjukkan awal
transfer data.

Kesimpulan / TLDR

Sebagian besar pernyataan dalam tipikal .bashrc hanya berguna untuk shell interaktif – tidak saat menjalankan perintah jarak jauh dengan rsh atau ssh . Dalam kebanyakan situasi seperti itu, pengaturan variabel shell, alias dan fungsi pendefinisian tidak diinginkan – dan mencetak teks apa pun ke standar keluar secara aktif berbahaya jika mentransfer file menggunakan program seperti scp atau sftp . Keluar setelah memverifikasi bahwa shell saat ini non-interaktif adalah perilaku teraman untuk .bashrc .


Linux
  1. Tujuan .bashrc Dan Bagaimana Cara Kerjanya?

  2. Bagaimana Cara Memeriksa Apakah Shell Masuk/interaktif/batch?

  3. Mengapa Pengguna Root Membutuhkan Izin Sudo?

  1. Jika Proses Mewarisi Lingkungan Induk, Mengapa Kita Perlu Ekspor?

  2. Setelah Saya Mengedit .bashrc Saya Mendapat Hantu Di Prompt?

  3. Mengapa Regex Di Bash Hanya Bekerja Jika Itu Adalah Variabel Dan Tidak Secara Langsung??

  1. Apa Arti Ampersand Di Akhir Baris Skrip Shell?

  2. Mengapa Ctrl + V tidak menempel di Bash (Linux shell)?

  3. Mengapa pengguna 'bin' memerlukan shell login?