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, biasanyarshd
, atau daemon shell amansshd
. 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 sebagaish
.--norc
opsi dapat digunakan untuk menghambat perilaku ini,
dan--rcfile
opsi dapat digunakan untuk memaksa file lain untuk dibaca, tetapi
tidak adarshd
atausshd
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).
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 (sepertifortune
,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 antarascp2
/sftp
dansftp-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 padaread(2)
. Sementara itu, setelah profil
shell diproses di sisi jarak jauh,scp
dalam mode sink dimulai,
yang juga memblokirread(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
.