Saya memiliki program pada host jarak jauh, yang pelaksanaannya perlu sayaotomatiskan. Perintah menjalankan program itu, pada mesin yang sama, terlihat seperti ini:
/path/to/program -a file1.txt -b file2.txt
Dalam hal ini, file1.txt
dan file2.txt
digunakan untuk hal-hal yang sepenuhnya berbeda dalam program, jadi saya tidak bisa hanya cat
bersama-sama. Namun, dalam kasus saya, file1.txt
dan file2.txt
yang ingin saya sampaikan ke program hanya ada di perangkat saya, bukan pada host tempat saya perlu menjalankan program. Saya tahu bahwa saya dapat memberi makan setidaknya satu file melalui SSH dengan mengirimkannya stdin
:
cat file1.txt | ssh host.name /path/to/program -a /dev/stdin -b file2.txt
tetapi, karena saya tidak diizinkan untuk menyimpan file di host, saya perlu cara untuk mendapatkan di file2.txt
sana juga. Saya berpikir itu mungkin melalui penyalahgunaan variabel lingkungan dan penggunaan kreatif cat
dan sed
bersama - sama, tapi saya tidak tahu alat cukup baik untuk memahami bagaimana saya akan menggunakannya untuk mencapai ini. Apakah bisa dilakukan, dan bagaimana?
sumber
cat
dansed
bukan solusinya di sini.Jawaban:
Jika file yang diberikan sebagai argumen untuk program Anda adalah file teks, dan Anda dapat mengontrol kontennya (Anda tahu baris yang tidak muncul di dalamnya), Anda dapat menggunakan beberapa dokumen di sini:
Berikut
cat
adalah contoh perintah yang menggunakan nama file sebagai argumen. Ini bisa jadi sebagai gantinya:Ganti masing
EOT
- masing dengan sesuatu yang tidak terjadi di masing-masing file, masing-masing.sumber
dash
(yang/bin/sh
di debian, ubuntu, dll),busybox sh
, yang/bin/sh
dari FreeBSD danyash
tidak menggunakan file-file sementara untuk di sini-dokumen. Saya sebenarnya sudah mengujinya dengan chroot read-only. Tentu saja,/dev/fd/
file - file itu harus tersedia - hanya tersedia sistem FreeBSD/dev/fd/0-2
, jadifdescfs
harus dipasang/dev/fd
.U+001C
adalah "Pemisah Informasi Empat" (pemisah file, FS) dan sangat ideal untuk kasus ini, meskipun file biner dapat menggunakannya secara kebetulan. Oleh karena itu, saya sarankanEOT="$(printf $'\x1c')"
di shell canggih atau yang lainEOT="$(awk 'BEGIN{printf"%c",28}')"
untuk kompatibilitas. Anda harus mengutipnya ketika Anda meletakkannya, sepertiecho "$EOT$EOT$EOT"
(tiga kali lipat untuk menurunkan kemungkinan mencocokkan file biner).tty
perintah? Kecuali saya melewatkan sesuatu - yang saya kira mungkin?Mungkin tidak persis seperti yang Anda inginkan ... Tapi mungkin mempertimbangkan mengirim tarball melalui pipa yang dibuka oleh ssh?
Anda mengatakan itu:
Mungkin saja Anda tidak memiliki direktori home yang dapat ditulisi atau lokasi lain yang nyaman untuk menyimpan file dalam jangka panjang, tetapi saya katakan itu tidak mungkin Anda tidak memiliki lokasi yang dapat ditulisi, meskipun hanya sementara
tmpfs
yang hanya tersedia untuk Anda koneksi tertentu.Banyak program (dan bahkan rutin libc) memerlukan program yang dapat ditulisi
/tmp
, sehingga kemungkinan besar program tersebut akan tersedia untuk Anda.Kemudian Anda bisa menggunakan skrip yang akan membongkar tarball ke direktori sementara, menjalankan program Anda dan membersihkan melalui koneksi ssh.
Sesuatu seperti:
Ini mungkin memerlukan perhatian ekstra dengan jalur file dan ada beberapa kasus sudut untuk dipertimbangkan (uji untuk mereka), tetapi pendekatan umum harus bekerja.
Jika tidak ada direktori yang bisa ditulisi, pendekatan yang mungkin adalah memodifikasi
program
untuk mengambil tarball sebagai input tunggal dan membongkar isinya ke memori. Misalnya, jikaprogram
adalah skrip Python, maka menggunakantarfile
modul bawaan akan dengan mudah mencapai sesuatu seperti itu.sumber
/tmp/
dan menggunakannya secara langsung.Jika Anda dapat mengatur pendengar TCP (bisa menjadi port yang lebih tinggi), maka Anda bisa menggunakan sesi SSH kedua untuk menetapkan sumber input kedua
nc
.Contoh:
Ada skrip ini di server (
~/script.bash
):Dan ada dua file ini secara lokal:
Sekarang pertama mulai sumber kedua (
$serv
adalah server):Dan jalankan perintah dengan benar:
sumber
Itu didirikan dalam komentar yang
/tmp
dapat ditulisi, jadi cukup salin ke salah satu file sebelumnya:Ini juga membersihkan file yang disalin setelah menjalankan yang sukses (ubah
&&
ke;
jika Anda ingin menghapusnya terlepas dari keberhasilan, tetapi kemudian perhatikan bahwa Anda akan kehilangan nilai keluar).Jika itu tidak dapat diterima, saya akan mengusulkan bermain-main dengan
/path/to/program
atau pembungkus untuk itu yang dapat memisahkan dua file dari aliran input tunggal seperti:Ini menggunakan pemisah informasi ASCII empat (pemisah file, FS) dan membuatnya tiga kali lipat sehingga kami meminimalkan kemungkinan file biner yang secara kebetulan berisi string itu. Anda
tweaked_program
kemudian akan membagi input yang diberikan pemisah dan kemudian beroperasi pada dua file yang disimpan sebagai variabel.Tentu saja, jika Anda menggunakan bahasa yang memiliki perpustakaan untuk menangani tarbal, pendekatan yang lebih aman dan lebih bersih adalah dengan menyalurkan
tar
ke kodessh
seperti ini:Dan Anda
tweaked_program
akan mendekompresi dan membuka arsip, menyimpan setiap file ke variabel yang berbeda, dan kemudian menjalankanprogram
logika asli pada variabel.sumber
Jika Anda diizinkan untuk meneruskan porta
ssh
, dan Anda memiliki akses kewget
pada mesin jarak jauh dan kebusybox
mesin lokal, Anda dapat melakukan sesuatu seperti:(menggunakan
cat
sebagai program contoh yang mengambil dua argumen file).Hanya kemampuan untuk meneruskan porta
-R
yang penting - alih-alih melakukan http, Anda dapat menggunakan metode lain, mis. jika Andanetcat
mendukung-d
dan-N
opsi:Mungkin ada cara untuk mengganti
<(...)
proses penggantian jika shell login pada mesin remote tidak seperti ksh atau bash-like.Secara keseluruhan, ini tidak terlalu bagus - pengetahuan yang lebih baik tentang sistem / shell / config / izin yang tepat (yang belum Anda berikan) dapat memungkinkan solusi yang lebih cerdas.
sumber
UPDATE: Ini tidak benar-benar bekerja, ssh memiliki ide yang sangat jelas tentang apa arti stdin dan stdout / stderr dan tidak benar-benar memungkinkan merebut stderr untuk membaca darinya. Saya akan menghapus jawaban ini dalam beberapa hari karena tidak berfungsi. Terima kasih untuk diskusi yang sangat menarik !!!
Sayangnya tidak ada cara yang bagus untuk melakukan ini secara langsung, karena
ssh
klien hanya akan meneruskan tiga deskriptor file (stdin
,stdout
danstderr
) ke server dan tidak memiliki ketentuan untuk meneruskan deskriptor file tambahan (yang akan membantu untuk kasus penggunaan khusus ini .)(Perhatikan juga bahwa protokol SSH memiliki ketentuan untuk meneruskan deskriptor file tambahan, hanya
ssh
klien yang tidak mengimplementasikan cara untuk menggunakan fitur itu. Secara teoritis, memperluas klien dengan tambalan akan cukup untuk mengekspos fitur ini.)Salah satu cara hacky untuk mencapai apa yang Anda cari adalah dengan menggunakan file descriptor 2 (
stderr
file descriptor) untuk mengirimkan file kedua. Sesuatu seperti:Ini harusnya berfungsi, itu hanya dapat menyebabkan masalah jika
program
mencoba menulis ke stderr. Anda dapat mengatasinya dengan menyulap ulang file deskriptor pada ujung jarak jauh sebelum Anda menjalankan program. Anda dapat memindahkanfile2.txt
ke file deskriptor 3 dan membuka kembali stderr ke mirror stdout:sumber
3<&2
adalah operator shell Bourne, dan sshd menjalankan shell login pengguna untuk menafsirkan perintah yang dikirim oleh klien)SSH_MSG_CHANNEL_EXTENDED_DATA
pesan dengan jenis yang disetel keSSH_EXTENDED_DATA_STDERR
. Anda dapat membaca semuanya di sini