Perbedaan antara 'ls' dan 'echo $ (ls)'


27

Pertimbangkan dua sampel cangkang

$ ls
myDoc.html
SomeDirectory
someDoc.txt

dan

$ echo $(ls)
myDoc.html SomeDirectory someDoc.txt

Yang pertama mengeksekusi lsyang, seperti yang saya mengerti, menambahkan isi direktori kerja saat ini ke stdoutfile (yang ditampilkan terminal). Apakah ini benar?

Yang kedua mengambil nilai lsperintah (yang artinya adalah isi dari direktori kerja saat ini) dan mencetaknya ke stdoutfile. Apakah ini benar?

Mengapa kedua perintah memberikan output yang berbeda?


1
karena Anda melakukan gema. Output ls sebagai input ke perintah echo.
ankidaemon

Ini adalah perilaku "yang diharapkan", yang akan segera dijelaskan oleh seseorang. Namun, apakah Anda yakin bahwa lsdengan sendirinya tidak memberi Anda beberapa item per baris?
roaima

@roaima ls kolom adalah sisa dari "fitur" bsd. versi unix mencetak satu entri per baris
Steve Cox

@SteveCox Saya belum pernah menggunakan UNIX sejak awal SVR4 jadi ingatan saya agak kabur. Terima kasih atas pengingatnya.
roaima

Mengapa tidak echo *?
jdh8

Jawaban:


70

Ketika Anda menjalankan perintah ini:

ls

terminal menampilkan output dari ls.

Ketika Anda menjalankan perintah ini:

echo $(ls)

shell menangkap output $(ls)dan melakukan pemisahan kata di atasnya. Dengan default IFS, ini berarti bahwa semua urutan ruang putih, termasuk karakter baris baru, diganti dengan satu kosong. Itu sebabnya output echo $(ls)muncul pada satu baris.

Untuk diskusi lanjutan tentang pemisahan kata, lihat FAQ Greg .

Menekan pemisahan kata

Shell tidak melakukan pemisahan kata pada string dalam tanda kutip. Dengan demikian, Anda dapat menekan pemisahan kata dan mempertahankan output multiline dengan:

echo "$(ls)"

ls dan output multiline

Anda mungkin memperhatikan bahwa lskadang - kadang mencetak lebih dari satu file per baris:

$ ls
file1  file2  file3  file4  file5  file6

Ini adalah default ketika output dari lspergi ke terminal. Ketika output tidak langsung ke terminal, lsubah default-nya ke satu file per baris:

$ echo "$(ls)"
file1
file2
file3
file4
file5
file6

Perilaku ini didokumentasikan dalam man ls.

Kehalusan lainnya: substitusi perintah dan mengikuti baris baru

$(...)adalah substitusi perintah dan shell menghapus karakter baris baru dari output substitusi perintah . Ini biasanya tidak terlihat karena, secara default, echomenambahkan satu baris baru ke akhir outputnya. Jadi, jika Anda kehilangan satu baris baru dari akhir $(...)dan Anda memperolehnya dari echosana, tidak ada perubahan. Namun, jika output dari perintah Anda berakhir dengan 2 atau lebih karakter baris baru sambil echomenambahkan kembali hanya satu, output Anda akan hilang satu atau lebih baris baru. Sebagai contoh, kita dapat menggunakan printfuntuk menghasilkan trailing karakter baris baru. Perhatikan bahwa kedua perintah berikut, meskipun jumlah baris baru berbeda, menghasilkan output yang sama dari satu baris kosong:

$ echo "$(printf "\n")"

$ echo "$(printf "\n\n\n\n\n")"

$ 

Perilaku ini didokumentasikan dalam man bash.

Kejutan lain: ekspansi pathname, dua kali

Mari kita membuat tiga file:

$ touch 'file?' file1 file2

Amati perbedaan antara ls file?dan echo $(ls file?):

$ ls file?
file?  file1  file2
$ echo $(ls file?)
file? file1 file2 file1 file2

Dalam kasus echo $(ls file?), file glob file?diperluas dua kali , menyebabkan nama file file1dan file2muncul dua kali dalam output. Ini karena, seperti yang ditunjukkan Jeffiekins, ekspansi pathname dilakukan terlebih dahulu oleh shell sebelum lsdijalankan dan kemudian lagi sebelum echodijalankan.

Perluasan pathname kedua dapat ditekan jika kami menggunakan tanda kutip ganda:

$ echo "$(ls file?)"
file?
file1
file2

4
selain itu, menggunakan isattyAnda dapat memeriksa apakah stdout adalah tty, ls menggunakan ini untuk menentukan apakah akan menggunakan warna atau tidak.
Janus Troelsen

1
Bukankah tanda kutip tidak cocok dalam cuplikan kode terakhir? Atau apakah $( )benar - benar memberikan penghalang sintaks sehingga Anda tidak perlu melakukan interpolasi?
kucing

6
@cat $()menyediakan penghalang sintaksis.
Random832

2
Satu lagi perbedaan penting: jika ada nama file yang mengandung karakter wildcard, echoperintah akan memperluas wildcard . Misalnya, jika lsmengembalikan file? file1 file2 , lalu echo $(ls)akan mengembalikan file? file1 file2 file1 file2 .
Jeffiekins

1
@Jeffiekins echotidak memperluas wildcard; shell tidak sebelum meneruskan ekspansi yang dihasilkan sebagai argumen untuk echo.
chepner

0

ls menyadari apakah ia mengirim output ke terminal atau tidak.

Menjalankan lspada prompt perintah akan menulis ke pseudo-tty Anda. Mengarahkan output dari lsumumnya tidak akan menjadi pseudo-tty, dan lsakan memformat output secara berbeda.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.