Saya telah belajar sendiri tentang bash scripting dan mengalami masalah. Saya telah menulis skrip untuk mengambil input dari pengguna, menggunakan perintah 'baca', dan menjadikan input tersebut variabel untuk digunakan nanti dalam skrip. Script berfungsi, tetapi ....
Saya ingin dapat mengaturnya menggunakan 'dialog'. Saya menemukan itu
'dialog --inputbox' akan mengarahkan output ke 'stderr' dan untuk mendapatkan input itu sebagai variabel, Anda harus mengarahkannya ke file dan kemudian mengambilnya. Kode yang saya temukan untuk menjelaskan ini adalah:
#!/bin/bash
dialog --inputbox \
"What is your username?" 0 0 2> /tmp/inputbox.tmp.$$
retval=$?
input=`cat /tmp/inputbox.tmp.$$`
rm -f /tmp/inputbox.tmp.$$
case $retval in
0)
echo "Your username is '$input'";;
1)
echo "Cancel pressed.";;
esac
Saya melihat bahwa ia mengirim sdterr ke /tmp/inputbox.tmp.$$ dengan 2>, tetapi file outputnya terlihat seperti 'inputbox.tmp.21661'. Ketika saya mencoba dan menyimpan file itu memberi saya kesalahan. Jadi saya masih tidak bisa mendapatkan input pengguna dari --inputbox sebagai variabel.
Contoh skrip:
echo " What app would you like to remove? "
read dead_app
sudo apt-get remove --purge $dead_app
Jadi seperti yang Anda lihat itu adalah skrip dasar. Apakah mungkin untuk mendapatkan variabel sebagai kata dari dialog --inputbox
?
mktemp
perintah untuk membuat file sementara.Jawaban:
^ jawaban dari @Sneetsher (4 Jul 2014)
Seperti yang diminta, saya akan mencoba menjelaskan apa yang dilakukan cuplikan ini baris demi baris.
Perhatikan bahwa saya akan menyederhanakannya dengan menghilangkan semua
;
titik koma di baris yang berakhir, karena mereka tidak perlu jika kita menulis satu perintah per baris.I / O - Streaming:
Pertama, Anda perlu memahami aliran komunikasi. Ada 10 aliran, diberi nomor dari 0 hingga 9:
Streaming 0 ("STDIN"):
"Input standar", aliran input default untuk membaca data dari keyboard.
Streaming 1 ("STDOUT"):
"Output standar", aliran output default yang digunakan untuk menampilkan teks normal di terminal.
Stream 2 ("STDERR"): "Standard error", aliran output default yang digunakan untuk menampilkan kesalahan atau teks lain untuk keperluan khusus di terminal.
Streaming 3-9: Streaming
tambahan, yang dapat digunakan secara bebas. Mereka tidak digunakan secara default dan tidak ada sampai ada sesuatu yang mencoba menggunakannya.
Perhatikan bahwa semua "aliran" diwakili secara internal oleh deskriptor file di
/dev/fd
(yang merupakan tautan simbolis/proc/self/fd
yang berisi tautan simbolis lain untuk setiap aliran ... ini sedikit rumit dan tidak penting untuk perilaku mereka, jadi saya berhenti di sini.). Streaming standar juga ada/dev/stdin
,/dev/stdout
dan/dev/stderr
(yang merupakan tautan simbolis lagi, dll ...).Naskah:
Bash built-in
exec
dapat digunakan untuk menerapkan pengalihan aliran ke shell, yang berarti mempengaruhi semua perintah berikut. Untuk info lebih lanjut, jalankanhelp exec
di terminal Anda.Dalam kasus khusus ini, stream 3 dialihkan ke stream 1 (STDOUT), itu berarti semua yang kami kirim ke stream 3 nanti akan muncul di terminal kami seolah-olah itu biasanya dicetak ke STDOUT.
Baris ini terdiri dari banyak bagian dan struktur sintaksis:
result=$(...)
Struktur ini mengeksekusi perintah dalam tanda kurung dan menetapkan output (STDOUT) ke variabel bash
result
. Dapat dibaca melalui$result
. Semua ini dijelaskan entah bagaimana di dapur kerasman bash
.dialog --inputbox TEXT HEIGHT WIDTH
Perintah ini menampilkan kotak TUI dengan TEXT yang diberikan, bidang input teks dan dua tombol OK dan BATAL. Jika OK dipilih, perintah keluar dengan status 0 dan mencetak teks yang dimasukkan ke STDERR, jika BATAL dipilih, itu akan keluar dengan kode 1 dan tidak mencetak apa pun. Untuk info lebih lanjut, baca
man dialog
.2>&1 1>&3
Ini adalah dua perintah pengalihan. Mereka akan ditafsirkan dari kanan ke kiri:
1>&3
mengarahkan aliran perintah 1 (STDOUT) ke aliran khusus 3.2>&1
pengalihan setelah itu aliran perintah 2 (STDERR) untuk streaming 1 (STDOUT).Itu berarti bahwa semua perintah yang dicetak ke STDOUT sekarang muncul di stream 3, sementara semua yang dimaksudkan untuk muncul di STDERR sekarang akan dialihkan ke STDOUT.
Jadi seluruh baris menampilkan prompt teks (pada STDOUT, yang dialihkan ke streaming 3, yang mana shell kembali kembali ke STDOUT pada akhirnya - lihat
exec 3>&1
perintah) dan memberikan data yang dimasukkan (dikembalikan melalui STDERR, kemudian diarahkan ke STDOUT) ke variabel Bashresult
.Kode ini mengambil kode keluar perintah yang sebelumnya dieksekusi (di sini dari
dialog
) melalui variabel Bash yang dipesan$?
(selalu memegang kode keluar terakhir) dan hanya menyimpannya dalam variabel Bash kita sendiriexitcode
. Itu bisa dibaca$exitcode
lagi. Anda dapat mencari lebih banyak info tentang ini diman bash
, tetapi itu mungkin perlu waktu ...Bash built-in
exec
dapat digunakan untuk menerapkan pengalihan aliran ke shell, yang berarti mempengaruhi semua perintah berikut. Untuk info lebih lanjut, jalankanhelp exec
di terminal Anda.Dalam kasus khusus ini, aliran 3 dialihkan ke "aliran -", yang artinya harus ditutup. Data yang dikirim ke streaming 3 tidak akan dialihkan ke mana pun lagi mulai sekarang.
echo
Perintah sederhana ini (info lebih lanjut tentangman echo
) hanya mencetak konten dari dua variabel Bashresult
danexitcode
ke STDOUT. Karena kami tidak memiliki pengalihan aliran eksplisit atau implisit di sini lagi, mereka akan benar-benar muncul di STDOUT dan karenanya ditampilkan di terminal. Sungguh keajaiban! ;-)Ringkasan:
Pertama, kami mengatur shell untuk mengarahkan kembali semua yang kami kirim ke custom stream 3 kembali ke STDOUT, sehingga muncul di terminal kami.
Kemudian kita menjalankan
dialog
perintah, mengarahkan STDOUT aslinya ke aliran kustom 3 kita, karena itu perlu ditampilkan pada akhirnya, tetapi untuk sementara kita perlu menggunakan aliran STDOUT untuk hal lain.Kami mengarahkan STDERR asli dari perintah, di mana input pengguna jendela dialog dikembalikan, ke STDOUT sesudahnya.
Sekarang kita dapat menangkap STDOUT (yang menyimpan data yang diarahkan dari STDERR) dan menyimpannya dalam variabel kita
$result
. Ini berisi input pengguna yang diinginkan sekarang!Kami juga menginginkan
dialog
kode keluar perintah, yang menunjukkan kepada kami apakah OK atau BATAL diklik. Nilai ini disajikan dalam variabel Bash yang dipesan$?
dan kami hanya menyalinnya ke variabel kami sendiri$exitcode
.Setelah itu kami menutup streaming 3 lagi, karena kami tidak membutuhkannya lagi, untuk menghentikan pengalihan lebih lanjut.
Akhirnya, kami biasanya menampilkan konten kedua variabel
$result
(input pengguna dari jendela dialog) dan$exitcode
(0 untuk OK, 1 untuk BATAL) ke terminal.sumber
exec
itu tidak perlu rumit. Mengapa tidak hanya kita--stdout
opsidialog
atau mengarahkan outputnya2>&1 >/dev/tty
?Menggunakan alat dialog sendiri: --output-fd flag
Jika Anda membaca halaman manual untuk dialog, ada opsi
--output-fd
, yang memungkinkan Anda untuk secara eksplisit mengatur di mana output berjalan (STDOUT 1, STDERR 2), alih-alih secara default pergi ke STDERR.Di bawah ini Anda dapat melihat saya menjalankan
dialog
perintah sampel , dengan secara eksplisit menyatakan bahwa output harus masuk ke file descriptor 1, yang memungkinkan saya untuk menyimpannya ke MYVAR.MYVAR=$(dialog --inputbox "THIS OUTPUT GOES TO FD 1" 25 25 --output-fd 1)
Menggunakan pipa bernama
Pendekatan alternatif yang memiliki banyak potensi tersembunyi, adalah dengan menggunakan sesuatu yang dikenal sebagai pipa bernama .
Tinjauan yang lebih mendalam tentang jawaban user.dz dengan pendekatan alternatif
Jawaban asli oleh user.dz dan penjelasan ByteCommander tentang keduanya memberikan solusi dan ikhtisar yang baik tentang apa yang dilakukannya. Namun, saya percaya analisis yang lebih dalam bisa bermanfaat untuk menjelaskan mengapa itu berhasil.
Pertama-tama, penting untuk memahami dua hal: apa masalah yang kita coba selesaikan dan apa yang menjadi dasar mekanisme shell yang kita hadapi. Tugasnya adalah untuk menangkap output dari suatu perintah melalui substitusi perintah. Di bawah gambaran sederhana yang diketahui semua orang, pergantian perintah menangkap
stdout
perintah dan membiarkannya digunakan kembali oleh sesuatu yang lain. Dalam hal ini,result=$(...)
bagian harus menyimpan output dari perintah apa pun yang ditunjuk oleh...
menjadi variabel yang dipanggilresult
.Di bawah kap, substitusi perintah sebenarnya diimplementasikan sebagai pipa, di mana ada proses anak (perintah aktual yang berjalan) dan proses membaca (yang menyimpan output ke variabel). Ini terbukti dengan jejak sederhana dari panggilan sistem. Perhatikan bahwa file deskriptor 3 adalah ujung baca dari pipa, sedangkan 4 adalah akhir tulis. Untuk proses anak
echo
, yang menulis kestdout
- file deskriptor 1, file deskriptor tersebut sebenarnya adalah salinan file deskriptor 4, yang merupakan akhir penulisan pipa. Perhatikan bahwastderr
ini tidak berperan di sini, hanya karena itu hanya pipa penghubungstdout
.Mari kita kembali ke jawaban semula. Karena sekarang kita tahu bahwa
dialog
menulis kotak TUI kestdout
, menjawabstderr
, dan dalam substitusi perintahstdout
disalurkan ke tempat lain, kita sudah memiliki bagian dari solusi - kita perlu me-rewire deskriptor file sedemikian rupa yangstderr
akan disalurkan ke proses pembaca. Ini adalah2>&1
bagian dari jawabannya. Namun, apa yang kita lakukan dengan kotak TUI?Di situlah file deskriptor 3 masuk.
dup2()
Syscall memungkinkan kita untuk menduplikasi deskriptor file, membuatnya secara efektif merujuk ke tempat yang sama, namun kita dapat memanipulasinya secara terpisah. File deskriptor dari proses yang memiliki terminal kontrol terpasang sebenarnya menunjuk ke perangkat terminal tertentu. Ini terbukti jika Anda melakukannyadi mana
/dev/pts/5
perangkat pseudo-terminal saya saat ini. Jadi, jika kita dapat menyimpan tujuan ini, kita masih dapat menulis kotak TUI ke layar terminal. Itu yangexec 3>&1
dilakukannya. Ketika Anda memanggil perintah dengan pengalihancommand > /dev/null
misalnya, shell melewati itu deskriptor file stdout dan kemudian menggunakandup2()
untuk menulis file deskriptor itu/dev/null
. Theexec
Perintah Melakukan sesuatu yang mirip dengandup2()
file descriptor untuk sesi shell utuh, sehingga membuat perintah mewarisi sudah diarahkan file descriptor. Sama denganexec 3>&1
. Deskriptor file3
sekarang akan merujuk ke / menunjuk ke terminal pengendali, dan perintah apa pun yang berjalan di sesi shell akan mengetahuinya.Jadi ketika
result=$(dialog --inputbox test 0 0 2>&1 1>&3);
terjadi, shell membuat pipa untuk dialog untuk menulis, tetapi juga2>&1
pertama-tama akan membuat file descriptor 2 perintah diduplikasi ke deskriptor file tulis dari pipa itu (sehingga membuat output pergi ke ujung baca pipa dan ke dalam variabel) , sementara file deskriptor 1 akan digandakan ke 3. Ini akan membuat file deskriptor 1 masih merujuk ke terminal pengendali, dan dialog TUI akan muncul di layar.Sekarang, sebenarnya ada jalan pintas untuk terminal pengontrol saat ini dari proses, yaitu
/dev/tty
. Dengan demikian, solusinya dapat disederhanakan tanpa menggunakan deskriptor file, cukup menjadi:Hal-hal penting untuk diingat:
Lihat juga
sumber
--stdout
opsi bisa berbahaya dan dengan mudah gagal pada beberapa sistem, dan saya pikir--output-fd 1
melakukan hal yang sama:--stdout: Direct output to the standard output. This option is provided for compatibility with Xdialog, however using it in portable scripts is not recommended, since curses normally writes its screen updates to the standard output. If you use this option, dialog attempts to reopen the terminal so it can write to the display. Depending on the platform and your environment, that may fail.
- Namun, ide pipa bernama itu keren!--output-fd
, yang merupakan opsi yang saya gunakan di sini, tidak--stdout
. Kedua, dialog sedang digambar pada stdout pertama, output yang dikembalikan adalah kedua. Kami tidak melakukan dua hal ini secara bersamaan. Namun,--output-fd
tidak secara khusus mengharuskan seseorang untuk menggunakan fd 1 (STDOUT). Itu dapat dengan mudah dialihkan ke deskriptor file lain: AKU tidak bisa menjelaskannya !!! Jika Anda dapat memahami apa yang mereka katakan dalam referensi: Panduan Bash-Scripting Lanjutan: Bab 20. I / O Redirection , tulis jawaban baru dan saya akan memberi Anda 50repBounty diberikan, untuk penjelasan, lihat jawaban ByteCommander . :) Ini adalah bagian dari sejarah.
Sumber: Dialog di bash tidak mengambil variabel dengan benar
Referensi: Panduan Script Bash Lanjutan: Bab 20. Pengarahan I / O
sumber
Ini bekerja untuk saya:
Halaman manual
dialog
menceritakan tentang --stdout:Adakah yang tahu di platform atau lingkungan mana itu tidak berfungsi? Apakah mengarahkan ulang
dialog
output2>&1 >/dev/tty
sebagai gantinya bekerja lebih baik?sumber
Jika ada orang lain yang mendarat di sini dari Google, dan meskipun pertanyaan ini meminta bash secara khusus, berikut adalah alternatif lain:
Anda dapat menggunakan zenity . Zenity adalah utilitas grafis yang dapat digunakan di dalam skrip bash. Tapi tentu saja ini akan membutuhkan server X seperti yang ditunjukkan oleh user877329.
Kemudian dalam skrip Anda:
Tautan yang bermanfaat .
sumber
dialog
. Ini seperti saya datang dan bertanya kepada Anda, "Bagaimana saya menulis ini dan itu dengan python?", Tetapi Anda memberi saya bash - saya sangat senang ini bisa dilakukan dengan cara yang berbeda, tapi bukan itu yang saya tanyakanJawaban yang diberikan oleh Sneetsher agak lebih elegan, tetapi saya dapat menjelaskan apa yang salah: Nilai
$$
berbeda di dalam backticks (karena itu memulai shell baru, dan$$
merupakan PID dari shell saat ini). Anda akan ingin memasukkan nama file dalam suatu variabel, kemudian merujuk ke variabel itu di seluruh.Dalam hal ini, menghindari file sementara akan menjadi solusi yang lebih baik, tetapi akan ada banyak situasi di mana Anda tidak dapat menghindari file temp.
sumber