perbedaan antara $ {} dan $ () dalam skrip shell

28
$ echo $(date)
Thu Jul 2 16:33:11 SGT 2015
$ echo ${date}

$ name=foo
$ echo $(name)
ksh: name:  not found

$ echo ${name}
foo

Sepertinya $ {variabel} sama dengan $ variabel. sementara $ () adalah untuk mengeksekusi perintah. Mengapa menggunakan $ {} saat itu?

Cupu
sumber
1
Terkait:  tidak berarti apa yang Anda pikirkan ...${ variable_name }
G-Man Mengatakan 'Reinstate Monica'

Jawaban:

39

$(command)adalah "substitusi perintah". Seperti yang Anda pahami, ia menjalankan command, menangkap outputnya, dan memasukkannya ke dalam baris perintah yang berisi $(…); misalnya,

$ ls -ld $(date +%B).txt
-rwxr-xr-x  1 Noob Noob    867 Jul  2 11:09 July.txt

${parameter}adalah "substitusi parameter". Banyak informasi dapat ditemukan di halaman manual shell, bash (1) , di bawah tajuk " Parameter Expansion ":

${parameter}
    Nilai parameter diganti. Kawat gigi diperlukan ketika parameter adalah parameter posisi dengan lebih dari satu digit, atau ketika parameter diikuti oleh karakter yang tidak dapat ditafsirkan sebagai bagian dari namanya.

Untuk parameter posisi, lihat “ Parameter Posisi ”, di bawah. Dalam penggunaannya yang paling umum, seperti yang ditunjukkan dalam jawaban lain, parameteradalah nama variabel. The ${…}bentuk, seperti yang dinyatakan pada akhir ayat di atas, memungkinkan Anda mendapatkan nilai variabel (yaitu, ) dan mengikutinya segera dengan surat, digit, atau garis bawah:$variable_name

$ hewan = kucing
$ echo $ animals
                                # Tidak ada variabel seperti "hewan".
$ echo $ {animal} s
kucing
$ echo $ animal_food
                                # Tidak ada variabel seperti "animal_food".
$ echo $ {animal} _food
makanan kucing

Anda juga dapat melakukan ini dengan kutipan:

$ echo "$ animal" s
kucing

Atau, sebagai latihan dalam opsi, Anda bisa menggunakan variabel kedua:

$ jamak = s
$ echo $ animal $ jamak
kucing

Tapi ini hanya langkah 1. Paragraf berikutnya di halaman manual menarik, meskipun sedikit samar:

Jika karakter pertama dari parameter adalah tanda seru ( !), suatu tingkat tipuan variabel diperkenalkan. Bash menggunakan nilai variabel yang dibentuk dari sisa parameter sebagai nama variabel; variabel ini kemudian diperluas dan nilai itu digunakan di seluruh substitusi, bukan nilai parameter itu sendiri. Ini dikenal sebagai ekspansi tidak langsung .     ... (pengecualian) ...    Tanda seru harus segera mengikuti penjepit kiri untuk memperkenalkan tipuan.

Saya tidak yakin bagaimana saya bisa membuat ini lebih jelas kecuali dengan contoh:

$ hewan = kucing
$ echo $ animal
kucing
$ cat = kucing
$ echo $ cat
kucing betina
$ echo $ {! animal}
kucing                            # Jika $ hewan adalah "kucing" , maka $ {! hewan} adalah $ kucing , yaitu, "kucing"

Jadi mari kita sebut langkah 1½ itu. Ada banyak hal menarik yang dapat Anda lakukan sebagai langkah 2:

$ hewan = kucing
$ echo $ {# animal}
3                                # Panjang string
$ echo $ {animal / at / ow}
sapi                              # Pergantian

Anda tidak dapat melakukan hal-hal itu tanpa {... }kawat gigi.

Parameter Posisi

Pertimbangkan contoh buatan ini :

$ cat myecho.sh
echo $ 1 $ 2 $ 3 $ 4 $ 5 $ 6 $ 7 $ 8 $ 9 $ 10 $ 11 $ 12 $ 13 $ 14 $ 15
$ ./myecho.sh. Hei diddle diddle, Kucing dan biola, Sapi melompati bulan.
Hei diddle diddle, The cat and the fiddle, The Hey0 Hey1 Hey2 Hey3 Hey4 Hey5

karena shell tidak mengerti $10, $11, dll memperlakukan $10seolah-olah itu ${1}0. Tetapi ia mengerti ${10}, ${11}dll., Sebagaimana disebutkan dalam halaman manual (“parameter posisi dengan lebih dari satu digit”).

Tapi jangan benar-benar menulis skrip seperti itu; ada cara yang lebih baik untuk menangani daftar argumen panjang.

Di atas (bersama dengan lebih banyak bentuk konstruksi) dibahas secara lebih panjang di halaman manual shell, bash (1) .${parameter…something_else}

Catatan tentang Harga

Perhatikan bahwa Anda harus selalu mengutip variabel shell kecuali Anda memiliki alasan yang kuat untuk tidak melakukannya, dan Anda yakin tahu apa yang Anda lakukan. Sebaliknya, meskipun kawat gigi bisa penting, mereka tidak sepenting kutipan.

$ filename = "nursery rhyme.txt"
$ ls -ld $ {nama file}
ls: tidak dapat mengakses kamar anak: Tidak ada file atau direktori seperti itu
ls: tidak dapat mengakses rhyme.txt: Tidak ada file atau direktori seperti itu
$ ls -ld "$ filename"
-rwxr-xr-x 1 Noob Noob 5309 2 Jul 11:09 pembibitan rhyme.txt

Itu juga berlaku untuk parameter posisi (yaitu, argumen baris perintah; misalnya, "$1") dan juga substitusi perintah:

$ ls -ld $ (tanggal "+% B% Y"). txt
ls: tidak dapat mengakses Juli: Tidak ada file atau direktori tersebut
ls: tidak dapat mengakses 2015.txt: Tidak ada file atau direktori tersebut
$ ls -ld "$ (tanggal" +% B% Y "). txt"
-rwxr-xr-x 1 Noob Noob 687 2 Jul 11:09 Juli 2015.txt

Lihat kutipan Bash yang tidak terhapus pada substitusi perintah untuk risalah singkat tentang interaksi antara kutipan dan $().

G-Man Mengatakan 'Reinstate Monica'
sumber
terima kasih untuk contoh yang luar biasa. Bisakah Anda menguraikan penggunaan! dalam contoh Anda. Saya tidak begitu mengerti bagaimana cara kerjanya.
Noob
@Noob: OK, saya menguraikan penggunaan !.
G-Man Mengatakan 'Reinstate Monica'
Terima kasih. Entah bagaimana! Sebenarnya hewan yang dimaksud adalah kucing variabel dan bukan kucing nilai. Bisakah Anda juga memberi tahu saya bagaimana / menjadi "c" dalam echo $ {animal / at / ow} Penjelasan pria tentang bash entah bagaimana ... saya tidak tahu. sulit dimengerti.
Noob
juga, dapatkah Anda menguraikan frasa ini - "$ {parameter} Nilai parameter diganti." diganti dengan apa? jika parameter adalah buah dan nilainya apel - buah = apel, jadi $ {buah} - apel diganti dengan ?? tidak benar-benar mendapatkan makna yang diganti di sini
Noob
@Noob: " ${!animal}sebenarnya merujuk ke variabel $catbukan nilai kucing." Ya, itulah intinya. "Bagaimana / at menjadi" c "dalam echo $ {animal / at / ow}?" Hah? / at tidak menjadi "c"; "Kucing" menjadi "sapi" ketika "at" diganti dengan "ow".
G-Man Mengatakan 'Reinstate Monica'
7

Dalam contoh Anda, $ var dan $ {var} identik. Namun, kurung kurawal berguna saat Anda ingin memperluas variabel dalam string:

    $ string=foo
    $ echo ${string}bar
      foobar
    $ echo $stringbar

    $ 

Dengan demikian kurung kurawal menyediakan sarana untuk mengganti variabel untuk mendapatkan nama variabel baru, itu sendiri untuk diganti.

MariusMatutiae
sumber
4

Saya biasanya melihatnya lebih umum di string. Sesuatu seperti ini tidak akan berfungsi:

var="a"
echo "$varRAW_STRING"

Tapi ini akan:

var="a"
echo "${var}RAW_STRING"

Seperti yang Anda katakan dengan benar, $()digunakan untuk menjalankan perintah:

dir_contents=$(ls)

Anda juga dapat menggunakan backticks, tetapi saya merasa $()lebih fleksibel. Untuk satu hal, backticks tidak dapat (mudah) disarangkan.

date_directory=`ls `date '+%Y-%m-%d'`` # Makes no sense
date_directory=$(ls $(date '+%Y-%m-%d')) # Much better
bytesized
sumber
Sebenarnya, tanda kutip mundur bisa menjadi bersarang: date_directory=`ls \`date '+%Y-%m-%d'\``. Tapi itu sangat jelek; $(…)jauh lebih jelas dan lebih mudah digunakan.
G-Man Mengatakan 'Reinstate Monica'
OK cukup adil. Secara teknis mungkin, tetapi saya tidak bisa membayangkan ada orang yang melakukannya hanya karena keterbacaannya
bytesized
1
Nah, `…`itu yang (hanya) sintaks untuk substitusi perintah selama bertahun-tahun sebelum $(…)ditemukan, sehingga Anda tidak perlu membayangkan apa pun - orang melakukannya.
G-Man Mengatakan 'Reinstate Monica'
s / ever
do