BASH dan Perilaku Pengembalian Gerbong

11

Saya punya satu pertanyaan singkat.
Apakah normal bahwa bash (saya menggunakan 4.4.11) tidak menampilkan baris / teks yang dipisahkan / diakhiri dengan polos \r?

Saya sedikit terkejut melihat perilaku ini:

$ a=$(printf "hello\ragain\rgeorge\r\n")
$ echo "$a"
george

Tapi teks "halo lagi" masih ada, entah bagaimana "tersembunyi":

$ echo "$a" |od -w32 -t x1c
0000000  68  65  6c  6c  6f  0d  61  67  61  69  6e  0d  67  65  6f  72  67  65  0d  0a
          h   e   l   l   o  \r   a   g   a   i   n  \r   g   e   o   r   g   e  \r  \n

Dan segera setelah kami bermain dengan bash baik-baik saja .... Tapi apakah ini risiko keamanan potensial? Bagaimana jika isi variabel "a" berasal dari dunia luar dan termasuk "perintah buruk" dan bukan hanya halo?

Tes lain, kali ini agak tidak aman:

$ a=$(printf "ls;\rGeorge\n")
$ echo "$a"
George
$ eval "$a"
0                   awkprof.out       event-tester.log  helloworld.c      oneshot.sh         rightclick-tester.py  tmp                    uinput-simple.py
<directory listing appears with an error message at the end for command George>

Bayangkan yang tersembunyi, rmbukan yang disembunyikan ls.

Perilaku yang sama saat menggunakan echo -e:

$ a=$(echo -e "ls;\rGeorge\r\n"); echo "$a"
George

Apakah saya yang melakukan sesuatu yang salah ...?

George Vasiliou
sumber

Jawaban:

20

echo "$a"Cetakan Anda "halo", lalu kembali ke awal baris (yang \rartinya), cetak "lagi", kembali lagi, cetak "george", kembali lagi, dan pergi ke baris berikutnya ( \n). Semuanya normal, tetapi seperti yang ditunjukkan chepner , itu tidak ada hubungannya dengan Bash: \rdan \ndiinterpretasikan oleh terminal, bukan oleh Bash (itulah sebabnya Anda mendapatkan output penuh saat Anda mengirim perintah ke pipa od).

Anda dapat melihat ini dengan lebih baik

$ a=$(printf "hellooooo\r  again,\rgeorge\r\n")
$ echo "$a"

karena itu akan meninggalkan akhir teks yang ditimpa:

georgen,o

Anda tidak dapat benar-benar menggunakannya untuk menyembunyikan perintah, hanya outputnya (dan hanya jika Anda bisa memastikan untuk menimpa dengan karakter yang cukup), kecuali menggunakan evalseperti yang Anda tunjukkan (tetapi menggunakan evalumumnya tidak disarankan). Trik yang lebih berbahaya adalah menggunakan CSS untuk menutupi perintah yang dimaksudkan untuk disalin dan ditempelkan dari situs web.

Stephen Kitt
sumber
Cukup jelas, terima kasih. Saya beruntung / tidak beruntung menggunakan kata terakhir dalam pengujian saya yang mampu menimpa sepenuhnya dua kata sebelumnya.
George Vasiliou
2
Perhatikan bahwa ini tidak ada hubungannya sama sekali bash; sepenuhnya ke terminal cara "menampilkan" carriage return, atau cara menampilkan karakter yang ditimpa. Sebagai contoh, itu akan sangat valid untuk terminal untuk ditampilkan -\r|sebagai sesuatu yang menyerupai tanda plus, bukan hanya pipa.
chepner
@ chepner Bagus untuk tahu! Terima kasih telah berbagi. Saya pikir ini hanya perilaku kasar.
George Vasiliou
@ GeorgeVasiliou Tidak, bashhanya menulis byte ke file; terserah siapa pun yang membaca byte tersebut untuk menafsirkannya.
chepner
Nitpick: printf, yang merupakan bash built-in command (meskipun juga ada sebagai executable mandiri), menafsirkan yang \r(urutan dua byte: 0x5cdan 0x72dan menghasilkan kembali kereta (satu byte: 0x0d.) Lalu, ya, terminal menafsirkan byte 0x0ddengan cara yang khusus, tetapi tidak menafsirkan string asli \r.
Suzanne DUPERON
6

Di dunia Unix, carriage return (umumnya disandikan seperti \rdalam bahasa pemrograman) adalah karakter kontrol yang tidak biasa. Anda dapat memiliki carriage return di dalam baris teks, seperti karakter lain selain dari feed baris (juga disebut baris baru ), yang menandai akhir baris.

Secara khusus, dalam skrip bash, carriage return adalah kata biasa karakter penyusunnya, seperti huruf dan angka. Setiap efek khusus dari carriage return berasal dari terminal, bukan dari shell.

Pengembalian carriage adalah karakter kontrol . Ketika Anda mencetaknya ke terminal, alih-alih menampilkan mesin terbang , terminal melakukan beberapa efek khusus. Untuk carriage return, efek khusus adalah memindahkan kursor ke awal baris saat ini. Jadi, jika Anda mencetak garis yang berisi carriage return di tengah, maka efeknya adalah bahwa paruh kedua ditulis di atas setengah pertama.

Beberapa karakter kontrol lainnya memiliki efek khusus: karakter backspace menggerakkan kursor ke kiri dengan satu posisi. Karakter bel menyebabkan terminal mengeluarkan suara atau menarik perhatian pengguna. Karakter pelarian memulai urutan pelarian yang dapat memiliki semua jenis efek khusus.

Jika Anda menampilkan output yang tidak dipercaya, Anda perlu menggosok atau melarikan diri karakter kontrol. Tidak hanya carriage return, tetapi juga beberapa lainnya, khususnya karakter escape, yang dapat menyebabkan semua jenis efek buruk. Lihat Bisakah “memelihara” file menjadi risiko keamanan potensial? dan Bagaimana cara menghindari serangan berurutan di terminal? untuk lebih lanjut tentang topik ini.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
0

Anda dapat melihat carriage return dalam variabel bash menggunakan printffungsi dengan %qformat.

$ TESTVAR="$(printf ' Version: 1 \r Build: 20180712 \r Test: 1324')"

$ printf %q $TESTVAR
Version:1$'\r'Build:20180712$'\r'Test:1324

Sumber dan bacaan lebih lanjut:

Nuwandame
sumber