Saya menulis sebuah skrip yang mengalihkan pengguna saat menjalankan, dan mengeksekusi menggunakan pengalihan file ke standar. Begitu user-switch.sh
juga ...
#!/bin/bash
whoami
sudo su -l root
whoami
Dan menjalankannya dengan bash
memberi saya perilaku yang saya harapkan
$ bash < user-switch.sh
vagrant
root
Namun, jika saya menjalankan skrip dengan sh
, saya mendapatkan output yang berbeda
$ sh < user-switch.sh
vagrant
vagrant
Mengapa bash < user-switch.sh
memberikan hasil yang berbeda dari sh < user-switch.sh
?
Catatan:
- terjadi pada dua kotak berbeda menjalankan Debian Jessie
bash
io-redirection
stdin
dash
popedotninja
sumber
sumber
sudo su
: unix.stackexchange.com/questions/218169/…/bin/sh
pada (salinan saya) Debian adalah Dash, ya. Aku bahkan tidak tahu apa itu sampai tadi. Saya terjebak dengan bash sampai sekarang.user-switch.sh
dalam pekerjaan Jenkins, dan skrip dieksekusi. Menjalankan skrip yang sama di luar Jenkins menghasilkan hasil yang berbeda, dan saya terpaksa mengajukan redirection untuk mendapatkan perilaku yang saya lihat di Jenkins.Jawaban:
Script yang serupa, tanpa
sudo
, tetapi hasil yang serupa:Dengan
bash
, sisa skrip berjalan sebagai input untuksed
, dengandash
, shell mengartikannya.Menjalankannya
strace
:dash
membaca satu blok skrip (delapan kB di sini, lebih dari cukup untuk menampung seluruh skrip), dan kemudian memunculkansed
:Yang berarti filehandle ada di akhir file, dan
sed
tidak akan melihat input apa pun. Bagian yang tersisa sedang disangga di dalamdash
. (Jika skrip lebih panjang dari ukuran blok 8 kB, bagian yang tersisa akan dibaca olehsed
.)Bash, di sisi lain, mencari kembali ke akhir perintah terakhir:
Jika input berasal dari pipa, seperti di sini:
rewinding tidak dapat dilakukan, karena pipa dan soket tidak dapat dicari. Dalam hal ini, Bash kembali membaca input karakter satu per satu untuk menghindari overreading. (
fd_to_buffered_stream()
dalaminput.c
) Melakukan panggilan sistem penuh untuk setiap byte pada prinsipnya tidak terlalu efektif. Dalam praktiknya, saya tidak berpikir bacaan akan menjadi biaya overhead yang besar dibandingkan misalnya fakta bahwa sebagian besar hal shell melibatkan pemijahan seluruh proses baru.Situasi serupa adalah ini:
Subshell harus memastikan
read
hanya membaca baris baru pertama, sehinggahead
melihat baris berikutnya. (Ini juga berfungsi dengan baikdash
.)Dengan kata lain, Bash berusaha lebih keras untuk mendukung membaca sumber yang sama untuk skrip itu sendiri, dan untuk perintah yang dijalankan darinya.
dash
tidak. Ituzsh
, danksh93
dikemas dalam Debian pergi dengan Bash pada ini.sumber
strace
nanti dan membandingkan output. Saya belum menggunakan pendekatan itu.Shell membaca skrip dari input standar. Di dalam skrip, Anda menjalankan perintah yang juga ingin membaca input standar. Masukan mana yang akan dituju? Anda tidak bisa mengatakan dengan andal .
Cara shell bekerja adalah mereka membaca sepotong kode sumber, menguraikannya, dan jika mereka menemukan perintah yang lengkap, jalankan perintah, kemudian lanjutkan dengan sisa potongan dan sisa file. Jika chunk tidak berisi perintah lengkap (dengan karakter terminating di akhir - saya pikir semua shell membaca hingga akhir baris), shell membaca chunk lain, dan seterusnya.
Jika perintah dalam skrip mencoba membaca dari deskriptor file yang sama dengan shell membaca skrip, maka perintah akan menemukan apa pun yang datang setelah potongan terakhir yang dibacanya. Lokasi ini tidak dapat diprediksi: tergantung pada ukuran cangkang yang dipilih, dan itu tidak hanya bergantung pada cangkang dan versinya tetapi juga pada konfigurasi mesin, memori yang tersedia, dll.
Bash mencari hingga akhir kode sumber perintah dalam skrip sebelum menjalankan perintah. Ini bukan sesuatu yang dapat Anda andalkan, tidak hanya karena shell lain tidak melakukannya, tetapi juga karena ini hanya berfungsi jika shell membaca dari file biasa. Jika shell membaca dari pipa (misalnya
ssh remote-host.example.com <local-script-file.sh
), data yang telah dibaca dibaca dan tidak dapat dibaca.Jika Anda ingin memberikan input ke perintah dalam skrip, Anda harus melakukannya secara eksplisit, biasanya dengan dokumen di sini . (Dokumen di sini biasanya yang paling nyaman untuk input multi-line, tetapi metode apa pun akan melakukannya.) Kode yang Anda tulis hanya berfungsi dalam beberapa shell, hanya jika skrip dilewatkan sebagai input ke shell dari file biasa; jika Anda berharap yang kedua
whoami
akan diteruskan sebagai inputsudo …
, pikirkan lagi, ingat bahwa sebagian besar waktu script tidak diteruskan ke input standar shell.Perhatikan bahwa dekade ini, dapat Anda gunakan
sudo -i root
. Menjalankansudo su
adalah peretasan dari masa lalu.sumber