Saya mencoba menulis skrip shell yang membuat beberapa direktori di server jauh dan kemudian menggunakan scp untuk menyalin file dari mesin lokal saya ke remote. Inilah yang saya miliki sejauh ini:
ssh -t user@server<<EOT
DEP_ROOT='/home/matthewr/releases'
datestamp=$(date +%Y%m%d%H%M%S)
REL_DIR=$DEP_ROOT"/"$datestamp
if [ ! -d "$DEP_ROOT" ]; then
echo "creating the root directory"
mkdir $DEP_ROOT
fi
mkdir $REL_DIR
exit
EOT
scp ./dir1 user@server:$REL_DIR
scp ./dir2 user@server:$REL_DIR
Setiap kali saya menjalankannya saya menerima pesan ini:
Pseudo-terminal will not be allocated because stdin is not a terminal.
Dan naskahnya hang selamanya.
Kunci publik saya dipercaya di server dan saya bisa menjalankan semua perintah di luar skrip dengan baik. Ada ide?
ssh user@server /bin/bash <<EOT…
/bin/bash
secara eksplisit adalah salah satu cara untuk menghindari masalah.Jawaban:
Coba
ssh -t -t
(ataussh -tt
singkatnya) untuk memaksakan alokasi pseudo-tty bahkan jika stdin bukan terminal.Lihat juga: Mengakhiri sesi SSH yang dijalankan oleh skrip bash
Dari ssh manpage:
sumber
ssh -t -t
dan tidakssh -tt
? Apakah ada perbedaan yang tidak saya sadari?Inappropriate IOCtl for device
-tt
dan-t -t
setara; menentukan argumen secara terpisah atau dihancurkan bersama-sama menjadi masalah gaya / preferensi pribadi, dan ketika sampai pada itu, ada argumen yang valid untuk melakukannya. tapi sungguh, itu hanya preferensi pribadi.Juga dengan opsi
-T
dari manualsumber
-tt
Opsi muncul paling baik bagi kita yang benar-benar menginginkan TTY dan mendapatkan pesan kesalahan OP. Ini-T
jawabannya adalah lebih baik jika Anda tidak perlu TTY tersebut.Per jawaban zanco , Anda tidak menyediakan perintah jarak jauh
ssh
, mengingat bagaimana shell mem-parsing baris perintah. Untuk mengatasi masalah ini, ubah sintaksssh
permintaan perintah Anda sehingga perintah jarak jauh terdiri dari string multi-line yang benar secara sintaksis.Ada berbagai sintaks yang bisa digunakan. Misalnya, karena perintah dapat disalurkan ke
bash
dansh
, dan mungkin juga shell lain, solusi paling sederhana adalah dengan hanya menggabungkanssh
permintaan shell dengan heredocs:Perhatikan bahwa mengeksekusi tanpa di atas
/bin/bash
akan menghasilkan peringatanPseudo-terminal will not be allocated because stdin is not a terminal
. Perhatikan juga yangEOT
dikelilingi oleh tanda kutip tunggal, sehinggabash
mengenali heredoc sebagai nowdoc , mematikan interpolasi variabel lokal sehingga teks perintah akan diteruskan apa adanyassh
.Jika Anda seorang penggemar pipa, Anda dapat menulis ulang di atas sebagai berikut:
Peringatan yang sama tentang
/bin/bash
berlaku untuk di atas.Pendekatan lain yang valid adalah untuk meneruskan perintah jarak jauh multi-line sebagai string tunggal, menggunakan beberapa lapisan
bash
interpolasi variabel sebagai berikut:Solusi di atas memperbaiki masalah ini dengan cara berikut:
ssh user@server
diuraikan oleh bash, dan ditafsirkan sebagaissh
perintah, diikuti oleh argumenuser@server
untuk diteruskan kessh
perintah"
memulai string interpolasi, yang ketika selesai, akan terdiri dari argumen untuk diteruskan kessh
perintah, yang dalam hal ini akan ditafsirkan denganssh
menjadi perintah jarak jauh untuk dieksekusi sebagaiuser@server
$(
memulai perintah yang akan dieksekusi, dengan output yang ditangkap oleh string interpolasi sekitarnyacat
adalah perintah untuk menampilkan isi file apa pun yang mengikuti. Output daricat
akan diteruskan kembali ke dalam string penangkap interpolasi<<
memulai bash heredoc'EOT'
menetapkan bahwa nama heredoc adalah EOT. Kutipan tunggal'
seputar EOT menentukan bahwa heredoc harus diuraikan sebagai nowdoc , yang merupakan bentuk khusus dari heredoc di mana isinya tidak diinterpolasi oleh bash, tetapi diteruskan dalam format literalKonten apa pun yang ditemui di antara
<<'EOT'
dan<newline>EOT<newline>
akan ditambahkan ke output nowdocEOT
mengakhiri nowdoc, menghasilkan file sementara nowdoc dibuat dan diteruskan kembali kecat
perintah panggilan .cat
output nowdoc dan meneruskan output kembali ke string interpolasi menangkap)
menyimpulkan perintah yang akan dieksekusi"
menyimpulkan string yang diinterpolasi menangkap. Isi dari string yang diinterpolasi akan dikembalikanssh
sebagai argumen baris perintah tunggal, yangssh
akan ditafsirkan sebagai perintah jarak jauh untuk dieksekusi sebagaiuser@server
Jika Anda perlu menghindari menggunakan alat eksternal seperti
cat
, dan tidak keberatan memiliki dua pernyataan, bukan satu, gunakanread
built-in dengan heredoc untuk menghasilkan perintah SSH:sumber
cat
solusi adalah bahwa hal itu dicapai dalam pernyataan tunggal (walaupun majemuk), dan tidak menghasilkan variabel sementara yang mencemari lingkungan shell.Saya menambahkan jawaban ini karena itu memecahkan masalah terkait yang saya alami dengan pesan kesalahan yang sama.
Masalah : Saya telah menginstal cygwin di Windows dan mendapatkan kesalahan ini:
Pseudo-terminal will not be allocated because stdin is not a terminal
Penyelesaian : Ternyata saya belum menginstal program dan utilitas klien openssh. Karena itu cygwin menggunakan implementasi ssh Windows, bukan versi cygwin. Solusinya adalah menginstal paket openssh cygwin.
sumber
$ which ssh/cygdrive/c/Program Files (x86)/Git/bin/ssh
openssh
ini mungkin cara yang tepat untuk Windows: superuser.com/a/301026/260710Pesan peringatan
Pseudo-terminal will not be allocated because stdin is not a terminal.
adalah karena fakta bahwa tidak ada perintah yang ditentukan untukssh
sementara stdin diarahkan dari dokumen di sini. Karena kurangnya perintah yang ditentukan sebagai argumenssh
pertama mengharapkan sesi login interaktif (yang akan membutuhkan alokasi pty pada host jarak jauh) tetapi kemudian harus menyadari bahwa stdin lokalnya adalah no tty / pty. Mengarahkanssh
stdin dari dokumen di sini biasanya memerlukan perintah (seperti/bin/sh
) untuk ditetapkan sebagai argumen untukssh
- dan dalam kasus seperti itu tidak ada pty yang akan dialokasikan pada host jarak jauh secara default.Karena tidak ada perintah yang harus dieksekusi melalui
ssh
yang membutuhkan kehadiran tty / pty (sepertivim
atautop
)-t
beralih kessh
berlebihan. Cukup gunakanssh -T user@server <<EOT ...
ataussh user@server /bin/bash <<EOT ...
dan peringatan akan hilang.Jika
<<EOF
tidak lolos atau kutip tunggal (yaitu<<\EOT
atau<<'EOT'
) variabel di dalam dokumen di sini akan diperluas oleh shell lokal sebelum dieksekusissh ...
. Efeknya adalah bahwa variabel-variabel di dalam dokumen di sini akan tetap kosong karena mereka hanya didefinisikan di shell jauh.Jadi, jika
$REL_DIR
harus dapat diakses oleh shell lokal dan didefinisikan dalam shell jauh,$REL_DIR
harus didefinisikan di luar dokumen di sini sebelumssh
perintah ( versi 1 di bawah); atau, jika<<\EOT
atau<<'EOT'
digunakan, output darissh
perintah dapat ditugaskan keREL_DIR
jika satu-satunya output darissh
perintah untuk stdout dihasilkan olehecho "$REL_DIR"
di dalam dokumen di sini lolos / dikutip tunggal ( versi 2 di bawah).Opsi ketiga adalah menyimpan dokumen di sini dalam sebuah variabel dan kemudian meneruskan variabel ini sebagai argumen perintah ke
ssh -t user@server "$heredoc"
( versi 3 di bawah).Dan, last but not least, bukan ide yang buruk untuk memeriksa apakah direktori pada host jarak jauh berhasil dibuat (lihat: periksa apakah file ada di host jarak jauh dengan ssh ).
sumber
Semua informasi yang relevan ada di jawaban yang ada, tetapi izinkan saya mencoba ringkasan pragmatis :
tl; dr:
Lewati perintah untuk dijalankan menggunakan argumen baris perintah :
ssh jdoe@server '...'
'...'
string dapat menjangkau beberapa baris, sehingga Anda dapat membuat kode Anda dapat dibaca bahkan tanpa menggunakan dokumen di sini:ssh jdoe@server ' ... '
JANGAN melewati perintah melalui stdin , seperti halnya ketika Anda menggunakan dokumen-sini :
ssh jdoe@server <<'EOF' # Do NOT do this ... EOF
Melewati perintah sebagai argumen berfungsi apa adanya, dan:
exit
pernyataan di akhir perintah, karena sesi akan keluar secara otomatis setelah perintah diproses.Singkatnya: meneruskan perintah melalui stdin adalah mekanisme yang bertentangan dengan
ssh
desain dan menyebabkan masalah yang kemudian harus diselesaikan.Baca terus, jika Anda ingin tahu lebih banyak.
Informasi latar belakang opsional:
ssh
Mekanisme untuk menerima perintah untuk dieksekusi pada server target adalah argumen baris perintah : operan terakhir (argumen non-opsi) menerima string yang berisi satu atau lebih perintah shell.Secara default, perintah
-T
ini berjalan tanpa pengawasan, dalam shell non-interaktif , tanpa menggunakan terminal (semu) (opsi tersirat), dan sesi secara otomatis berakhir ketika perintah terakhir selesai diproses.Jika perintah Anda memerlukan interaksi pengguna , seperti merespons permintaan interaktif, Anda dapat secara eksplisit meminta pembuatan pty (pseudo-tty) , terminal pseudo, yang memungkinkan berinteraksi dengan sesi jarak jauh, menggunakan
-t
opsi; misalnya:ssh -t jdoe@server 'read -p "Enter something: "; echo "Entered: [$REPLY]"'
Perhatikan bahwa
read
prompt interaktif hanya berfungsi dengan benar dengan pty, sehingga-t
opsi diperlukan.Menggunakan pty memiliki efek samping yang mencolok: stdout dan stderr digabungkan dan keduanya dilaporkan melalui stdout ; dengan kata lain: Anda kehilangan perbedaan antara output reguler dan kesalahan; misalnya:
ssh jdoe@server 'echo out; echo err >&2' # OK - stdout and stderr separate
ssh -t jdoe@server 'echo out; echo err >&2' # !! stdout + stderr -> stdout
Dengan tidak adanya argumen ini,
ssh
buat shell interaktif - termasuk ketika Anda mengirim perintah melalui stdin , yang merupakan awal masalah:Untuk shell interaktif ,
ssh
biasanya mengalokasikan pty (pseudo-terminal) secara default, kecuali jika stdinnya tidak terhubung ke terminal (nyata).Mengirim perintah melalui stdin berarti
ssh
stdin tidak lagi terhubung ke terminal, jadi tidak ada pty yang dibuat, danssh
memperingatkan Anda :Pseudo-terminal will not be allocated because stdin is not a terminal.
Bahkan
-t
opsi, yang tujuan utamanya adalah untuk meminta pembuatan pty, tidak cukup dalam hal ini : Anda akan mendapatkan peringatan yang sama.Agak anehnya, Anda kemudian harus dua kali lipat pada
-t
pilihan untuk penciptaan kekuatan sebuah pty:ssh -t -t ...
ataussh -tt ...
menunjukkan bahwa Anda benar-benar, benar-benar serius .Mungkin alasan untuk memerlukan langkah yang disengaja ini adalah bahwa hal - hal mungkin tidak berfungsi seperti yang diharapkan . Sebagai contoh, pada macOS 10.12, padanan yang tampak dari perintah di atas, memberikan perintah melalui stdin dan menggunakan
-tt
, tidak bekerja dengan baik; sesi macet setelah menanggapiread
prompt:ssh -tt jdoe@server <<<'read -p "Enter something: "; echo "Entered: [$REPLY]"'
Jika perintah yang ingin Anda sampaikan sebagai argumen membuat baris perintah terlalu panjang untuk sistem Anda (jika panjangnya mendekati
getconf ARG_MAX
- lihat artikel ini ), pertimbangkan menyalin kode ke sistem jarak jauh dalam bentuk skrip terlebih dahulu ( menggunakan, misalnya,scp
), dan kemudian mengirim perintah untuk menjalankan skrip itu.Dalam keadaan darurat, gunakan
-T
, dan berikan perintah melalui stdin , denganexit
perintah tambahan, tetapi perhatikan bahwa jika Anda juga membutuhkan fitur interaktif, penggunaan-tt
sebagai pengganti-T
mungkin tidak berfungsi.sumber
Saya tidak tahu dari mana hang itu berasal, tetapi mengarahkan ulang (atau menyalurkan) perintah ke ssh interaktif secara umum merupakan resep untuk masalah. Lebih kuat untuk menggunakan gaya perintah-untuk-menjalankan-sebagai-argumen-terakhir dan meneruskan skrip pada baris perintah ssh:
(Semua dalam satu
'
argumen baris perintah multiline -delimited raksasa ).Pesan pseudo-terminal adalah karena Anda
-t
yang meminta ssh untuk mencoba membuat lingkungan yang dijalankan pada mesin jarak jauh terlihat seperti terminal aktual untuk program yang berjalan di sana. Klien ssh Anda menolak untuk melakukan itu karena itu input standarnya sendiri bukan terminal, sehingga tidak memiliki cara untuk meneruskan API terminal khusus dan seterusnya dari mesin jarak jauh ke terminal Anda yang sebenarnya di ujung lokal.Lagi pula, apa yang ingin Anda capai
-t
?sumber
-T
sebagai gantinya.Setelah membaca banyak jawaban ini saya pikir saya akan membagikan solusi yang dihasilkan. Yang saya tambahkan adalah
/bin/bash
sebelum heredoc dan tidak memberikan kesalahan lagi.Gunakan ini:
Alih-alih ini (memberikan kesalahan):
Atau gunakan ini:
Alih-alih ini (memberikan kesalahan):
EKSTRA :
Jika Anda masih menginginkan prompt interaktif jarak jauh mis. Jika skrip yang Anda jalankan dari jarak jauh meminta kata sandi atau informasi lainnya, karena solusi sebelumnya tidak memungkinkan Anda untuk mengetikkan prompt.
Dan jika Anda juga ingin mencatat seluruh sesi dalam file
logfile.log
:sumber
Saya mengalami kesalahan yang sama di bawah Windows menggunakan emacs 24.5.1 untuk terhubung ke beberapa server perusahaan melalui / ssh: user @ host. Apa yang memecahkan masalah saya adalah menyetel variabel "tramp-default-method" menjadi "plink" dan setiap kali saya terhubung ke server saya mengabaikan protokol ssh. Anda perlu menginstal plink.exe Putty agar ini berfungsi.
Larutan
sumber
ssh -t foobar @ localhost yourscript.pl
sumber
-t
juga menggunakan , tetapi dalam skenario spesifik mereka itu tidak cukup, yang mendorong pertanyaan untuk memulai.