Mengapa perintah jarak jauh SSH mendapatkan lebih sedikit variabel lingkungan daripada saat dijalankan secara manual? [Tutup]

239

Saya memiliki perintah yang berjalan dengan baik jika saya ssh ke mesin dan menjalankannya, tetapi gagal ketika saya mencoba menjalankannya menggunakan perintah ssh jarak jauh seperti:

ssh user@IP <command>

Membandingkan output "env" menggunakan kedua metode resutl di lingkungan yang berbeda. Ketika saya masuk secara manual ke mesin dan menjalankan env, saya mendapatkan lebih banyak variabel lingkungan kemudian ketika saya menjalankan:

ssh user@IP "env"

Ada yang tahu kenapa?

Tom Feiner
sumber
30
Kenapa sebenarnya pertanyaan ini ditutup sebagai off topic?
jottr
13
Mungkin karena tidak terkait pemrograman. Seharusnya dipindahkan ke Pengguna Super alih-alih ditutup.
Daniel H
8
bashbukan bahasa scripting?
Dan Nissenbaum
Di Debian 8 saya harus mengganti shell untuk bash di / etc / passwd untuk beberapa alasan Bahkan dasbor rekonfigurasi ulang untuk membiarkan / bin / sh menunjuk ke bash tidak membantu.
user1050755

Jawaban:

173

Ada berbagai jenis kerang. Shell eksekusi perintah SSH adalah shell non-interaktif, sedangkan shell normal Anda adalah shell login atau shell interaktif. Deskripsi berikut, dari man bash:

       Shell login adalah karakter argumen pertama
       nol adalah -, atau yang dimulai dengan opsi --login.

       Shell interaktif adalah yang dimulai tanpa non-opsi
       argumen dan tanpa opsi -c yang input standarnya
       dan error keduanya terhubung ke terminal (seperti yang ditentukan
       oleh isatty (3)), atau yang dimulai dengan opsi -i. PS1 adalah
       set dan $ - termasuk saya jika bash bersifat interaktif, memungkinkan a
       skrip shell atau file startup untuk menguji keadaan ini.

       Paragraf berikut menjelaskan bagaimana bash mengeksekusi
       file startup. Jika ada file yang ada tetapi tidak bisa
       baca, bash melaporkan kesalahan. Tilde diperluas dalam file
       nama seperti yang dijelaskan di bawah di bawah Ekspansi Tilde di
       Bagian EKSPANSI.

       Ketika bash dipanggil sebagai shell login interaktif, atau sebagai
       shell non-interaktif dengan opsi --login, pertama-tama
       membaca dan mengeksekusi perintah dari file / etc / profile, jika
       file itu ada. Setelah membaca file itu, ia mencari
       ~ / .bash_profile, ~ / .bash_login, dan ~ / .profile, dalam
       memesan, dan membaca serta menjalankan perintah dari yang pertama
       yang ada dan dapat dibaca. Opsi --noprofile mungkin
       digunakan ketika shell mulai menghambat behav ini
       ior.

       Ketika shell login keluar, bash membaca dan mengeksekusi perintah
       dari file ~ / .bash_logout, jika ada.

       Ketika shell interaktif itu bukan shell login
       dimulai, bash membaca dan menjalankan perintah dari ~ / .bashrc,
       jika file itu ada. Ini dapat dihambat dengan menggunakan
       Opsi --norc. Opsi file --rcfile akan memaksa bash
       untuk membaca dan menjalankan perintah dari file alih-alih
       ~ / .bashrc.

       Ketika bash dimulai secara non-interaktif, untuk menjalankan shell
       skrip, misalnya, mencari variabel BASH_ENV di
       lingkungan, perluas nilainya jika muncul di sana,
       dan menggunakan nilai yang diperluas sebagai nama file untuk dibaca
       dan jalankan. Bash berperilaku seolah-olah perintah berikut
       dieksekusi:
              jika [-n "$ BASH_ENV"]; kemudian . "$ BASH_ENV"; fi
       tetapi nilai variabel PATH tidak digunakan untuk mencari
       untuk nama file.

Vinko Vrsalovic
sumber
7
Jawaban bagus, ini persis masalah, variabel lingkungan yang diperlukan tinggal di / etc / bashrc, yang tidak bersumber dalam mode non interaktif. Memindahkan mereka ke / etc / profile memecahkan masalah. Terima kasih banyak!
Tom Feiner
1
Jawaban ini hanya sebagian solusi. Berikut beberapa informasi lebih lanjut: tambahkan variabel lingkungan yang berbeda (mis. Ekspor SOURCED_SYSTEM_ETC_BASHRC) ke berbagai file yang bersumber: / etc / profile, etc / bashrc, ~ / .profile, ~ / .bash_profile, ~ / bashrc. Kemudian cari variabel unik dalam output Jenkins. Dalam kasus saya, saya memperbarui / etc / bashrc untuk mengandung 'export SOURCED_SYSTEM_ETC_BASHRC = yes', dan variabel itu muncul di log Jenkins untuk node. Jadi dalam kasus saya, untuk mengatur variabel lingkungan untuk budak jenkins mereka harus masuk ke / etc / bashrc. Login Jenkins ssh hanya bersumber / etc / bashrc.
Coder Roadie
Koreksi: Maksud saya /etc/bash.bashrc, bukan / etc / bashrc.
Coder Roadie
37
Itu cukup dinding teks, saya pikir itu akan layak menyoroti yang ssh user@host "bash --login -c 'command arg1 ...'"akan membuat remote shell mengatur lingkungan login. Bagian yang Anda kutip tidak menyebutkan --logintetapi akan mudah untuk mengabaikan ini.
codebeard
Terima kasih atas posting ini, saya biasa ssh <ssh options> <IP> bash --login my_script.shmenjalankan skrip pada mesin jarak jauh, bekerja dengan baik dan memungkinkan saya untuk berhasil menggunakan vars lokal sepertiJAVA_HOME
markc
117

Bagaimana dengan sumber profil sebelum menjalankan perintah?

ssh user@host "source /etc/profile; /path/script.sh"

Anda mungkin merasa terbaik untuk mengubah itu untuk ~/.bash_profile, ~/.bashrc, atau apa pun.

(Seperti di sini (linuxquestions.org) )

Ian Vaughan
sumber
1
Punya masalah ini, solusi ini bekerja dengan baik.
Sam152
10
Harus selalu mengetik kode tambahan hanya untuk sumber lingkungan itu konyol!
Michael
4
Orang jarang berulang kali mengetikkan hal-hal semacam ini, biasanya dalam skrip, dan dengan demikian, tidak masalah berapa banyak "kode tambahan" yang ada, asalkan bekerja: tm:
Ian Vaughan
1
Jika saya sumber / etc / profile dan ~ / .bash_profile (untuk mendapatkan tambahan pengguna ke path) itu berfungsi, tetapi itu jelek. Harus ada cara yang lebih mudah untuk memberi tahu perintah (dalam kasus saya xterm) untuk menggunakan login "interaktif" dan berakhir dengan jalur khusus pengguna lengkap pada mesin jarak jauh?
Jess
ssh $ 1 "source ~ / .bashrc; ~ / temp_unix.sh" Di sini temp_unix.sh telah mengekspor MANI_HOME = "mani deepak" tetapi tidak berfungsi.
mani deepak
90

Lingkungan Shell tidak memuat saat menjalankan perintah ssh jarak jauh. Anda dapat mengedit file lingkungan ssh:

vi ~/.ssh/environment

Formatnya adalah:

VAR1=VALUE1
VAR2=VALUE2

Juga, periksa sshdkonfigurasi untuk PermitUserEnvironment=yesopsi.

dpedro
sumber
1
kesempurnaan! +100 kalau bisa :)
Dexter
VisualGDB gagal dengan kesalahan "bash: gcc: command not found" dan solusi ini diperbaiki.
KalenGi
fantastis. Seandainya saya tahu tentang ini tahun lalu.
gravitasi
Ini jawaban yang sempurna!
Jirapong
1
@ pg2455 sementara Anda tidak selalu dapat mengkonfigurasi sshd di server Anda (atau tidak ingin mengaktifkannya untuk semua), Anda masih dapat mengedit lingkungan pengguna Anda
dpedro
63

Saya memiliki masalah yang sama, tetapi pada akhirnya saya menemukan bahwa ~ / .bashrc yang saya butuhkan.

Namun, di Ubuntu, saya harus mengomentari baris yang berhenti memproses ~ / .bashrc:

#If not running interactively, don't do anything
[ -z "$PS1" ] && return
tomaszbak
sumber
8
Atau, Anda bisa meletakkan semua kode "non-interaktif" Anda di atas baris itu.
machineghost
cantik, menyelamatkan saya banyak waktu :) terima kasih
Lance Pollard
Terima kasih. Hanya menambahkan bahwa file dengan pernyataan pengembalian dapat ditemukan di /etc/bash.bashrc.
adarshr
Apakah ada cara untuk mem-bypass kode ini di server tanpa mengubahnya?
Yoni
Saya menghabiskan banyak waktu untuk mencoba memahami mengapa skrip saya tidak berfungsi. Siapa yang mengira itu adalah ide yang bagus untuk meletakkan baris-baris ini di .bashrc ???
Sharcoux
4

Saya menemukan resolusi mudah untuk masalah ini adalah menambahkan sumber / etc / profile ke bagian atas file script.sh yang saya coba jalankan pada sistem target. Pada sistem di sini, ini menyebabkan variabel lingkungan yang diperlukan oleh script.sh dikonfigurasikan seolah-olah berjalan dari shell login.

Dalam salah satu tanggapan sebelumnya disarankan bahwa ~ / .bashr_profile dll ... digunakan. Saya tidak menghabiskan banyak waktu untuk hal ini tetapi, masalah dengan ini adalah jika Anda ssh ke pengguna yang berbeda pada sistem target daripada shell pada sistem sumber dari mana Anda masuk nampak bagi saya bahwa ini menyebabkan pengguna sistem sumber nama yang akan digunakan untuk ~.

Membuang
sumber
Sempurna! Solusi satu garis yang bagus untuk masalah ini.
corpico
3

Cukup ekspor variabel lingkungan yang Anda inginkan di atas centang untuk shell non-interaktif di ~ / .bashrc.

Michael MacDonald
sumber