Pertimbangkan ini:
$ ssh localhost bash -c 'export foo=bar'
terdon@localhost's password:
declare -x DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
declare -x HOME="/home/terdon"
declare -x LOGNAME="terdon"
declare -x MAIL="/var/spool/mail/terdon"
declare -x OLDPWD
declare -x PATH="/usr/bin:/bin:/usr/sbin:/sbin"
declare -x PWD="/home/terdon"
declare -x SHELL="/bin/bash"
declare -x SHLVL="2"
declare -x SSH_CLIENT="::1 55858 22"
declare -x SSH_CONNECTION="::1 55858 ::1 22"
declare -x USER="terdon"
declare -x XDG_RUNTIME_DIR="/run/user/1000"
declare -x XDG_SESSION_ID="c5"
declare -x _="/usr/bin/bash"
Mengapa mengekspor variabel dalam bash -c
sesi berjalan melalui ssh menghasilkan daftar declare -x
perintah (daftar variabel yang saat ini diekspor, sejauh yang saya tahu)?
Menjalankan hal yang sama tanpa bash -c
melakukan itu:
$ ssh localhost 'export foo=bar'
terdon@localhost's password:
$
Juga tidak akan terjadi jika kita tidak export
:
$ ssh localhost bash -c 'foo=bar'
terdon@localhost's password:
$
Saya menguji ini dengan sshing dari satu mesin Ubuntu ke yang lain (keduanya menjalankan bash 4.3.11) dan pada mesin Arch, sshing untuk dirinya sendiri seperti yang ditunjukkan di atas (bash versi 4.4.5).
Apa yang terjadi di sini? Mengapa mengekspor variabel di dalam bash -c
panggilan menghasilkan output ini?
export
. Zsh melakukan hal yang sama.export
, saya mencoba memahami apa yang sedang terjadi. Saya akan mengedit untuk menjelaskan bahwa ini hanya terjadi ketika mengekspor.export
dijalankan sendiri? Itu saya tidak mengerti.foo=bar
tidak muncul dalam daftar.Jawaban:
Ketika Anda menjalankan perintah
ssh
, itu dijalankan dengan memanggil Anda$SHELL
dengan-c
bendera:Jadi,
ssh remote_host "bash -c foo"
sebenarnya akan dijalankan:Sekarang, karena perintah yang Anda jalankan (
export foo=bar
) berisi spasi dan tidak dikutip dengan benar untuk membentuk keseluruhan,export
diambil sebagai perintah untuk dijalankan dan sisanya disimpan dalam array parameter posisi. Ini berartiexport
dijalankan danfoo=bar
diteruskan sebagai$0
. Hasil akhirnya sama dengan berlariPerintah yang benar adalah:
sumber
ssh
menyatukan argumen dengan spasi dan meminta shell login dari pengguna jarak jauh menafsirkannya, jadi di:ssh
meminta shell jarak jauh untuk menafsirkanperintah (pada dasarnya, jika host jarak jauh seperti Unix, itu akan menjalankan shell jarak jauh dengan
the-shell
,-c
danbash -c export foo=bar
sebagai argumen).Sebagian besar shell akan menafsirkan bahwa baris perintah sebagai menjalankan
bash
perintah denganbash
,-c
,export
danfoo=bar
sebagai argumen (jadi lariexport
sambil$0
berisifoo=bar
) saat Anda ingin menjalankannya denganbash
,-c
danexport foo=bar
sebagai argumen.Untuk itu, Anda harus menggunakan baris perintah seperti:
(atau:
untuk itu) jadi:
baris perintah dilewatkan ke shell jarak jauh. Baris perintah itu akan ditafsirkan oleh sebagian besar shell sebagai menjalankan
bash
perintahbash
,-c
danexport foo=bar
sebagai argumen. Perhatikan bahwa menggunakantidak akan berfungsi jika shell login dari pengguna jarak jauh adalah
rc
ataues
misalnya di mana"
bukan operator mengutip khusus. Kutipan tunggal adalah operator mengutip paling portabel (meskipun ada beberapa variasi tentang bagaimana mereka ditafsirkan antara shell, lihat Bagaimana menjalankan perintah sederhana sewenang-wenang atas ssh tanpa mengetahui shell login dari pengguna jarak jauh? Untuk lebih lanjut tentang itu).sumber