Subshells & Process Substitution — Terminal

Subshells & Process Substitution Shell menyediakan beberapa cara menggabungkan perintah — subshell, grouped commands, command substitution, dan process…

Subshell adalah salinan shell-mu yang jalan sebagai proses anak. Si anak mewarisi semua variabel dan folder induknya, tapi apa pun yang dia ubah gak balik ke induk. Bayangkan fotokopi dokumen: kamu boleh mencoret-coret fotokopiannya, dokumen aslinya tetap bersih. Kurung biasa ( ) artinya kerja di fotokopian. Kurung kurawal { ...; } artinya kerja langsung di dokumen asli.

🧪 Tebakan cepat: kamu menjalankan X=1, lalu (X=99), lalu echo $X. Yang tercetak 1 atau 99? Tebak dulu, jawabannya ada di bagian "Subshell ( ): kerja di salinan".

Subshell ( ): kerja di salinan

Semua contoh di pelajaran ini mulai dari folder /home/budi/proyek:

$ X=1
$ (X=99; echo "dalam: $X")
dalam: 99
$ echo "luar: $X"
luar: 1
$ (cd /tmp && pwd)
/tmp
$ pwd
/home/budi/proyek

Ini berguna kalau kamu mau mengubah sesuatu sebentar tanpa mengotori shell-mu. Contohnya (export NODE_ENV=production; npm run build): setelah build selesai, NODE_ENV di terminalmu tetap seperti sebelumnya.

Grup { ...; }: kerja di aslinya

$ X=1
$ { X=99; echo "dalam: $X"; }
dalam: 99
$ echo "luar: $X"
luar: 99

Kurung kurawal cuma mengelompokkan perintah. Gak ada salinan, jadi perubahannya bertahan. Penulisannya rewel: harus ada spasi setelah { dan titik koma (atau baris baru) sebelum }. Kegunaan utamanya: satu redirect untuk banyak perintah, misalnya { echo "== laporan =="; date; } > laporan.txt.

$( ): ambil output jadi teks

Command substitution menjalankan perintah di subshell, lalu menaruh output-nya (tanpa baris baru di ujung) di tempat itu:

$ JUMLAH=$(wc -l < daftar.txt)
$ echo "ada $JUMLAH baris"
ada 3 baris
$ Y=$(X=5; echo "$X")
$ echo "Y=$Y X=$X"
Y=5 X=1

<( ): output perintah sebagai file

Ada perintah yang cuma mau menerima nama file, misalnya diff dan comm. Process substitution <(perintah) menjalankan perintah itu di subshell, lalu memberikan sebuah nama file khusus yang isinya output perintah tersebut:

$ cat a.txt
banana
apple
cherry
$ cat b.txt
apple
cherry
date
$ echo <(sort a.txt)
/dev/fd/63
$ comm -12 <(sort a.txt) <(sort b.txt)
apple
cherry
$ diff <(sort a.txt) <(sort b.txt)
2d1
< banana
3a3
> date

Pipe juga bikin subshell

Di bash, tiap bagian pipe jalan di subshell sendiri. Akibatnya:

$ X=1
$ echo 99 | read X
$ echo $X
1
$ read X < <(echo 99)
$ echo $X
99

read X di ujung pipe mengisi X milik salinannya, lalu salinannya dibuang. Dengan < <(echo 99), read jalan di shell induk dan membaca dari process substitution, jadi X benar-benar berubah. Alasan yang sama membuat while read baris; do ...; done < file lebih aman daripada cat file | while read baris.

Pola Subshell? Mengubah induk? Dipakai untuk
( ... ) ya gak coba-coba cd atau variabel tanpa mengotori shell
{ ...; } gak ya mengelompokkan perintah, satu redirect untuk semua
$( ... ) ya gak mengambil output jadi teks
<( ... ) ya gak memberi output ke perintah yang minta nama file
a | b ya, tiap bagian gak menyambung output ke input

⚠️ Jebakan yang sering ketemu

TL;DR: Subshell adalah salinan shell: mewarisi variabel dan folder, tapi perubahannya gak balik ke induk. ( ... ) jalan di salinan, jadi X=1; (X=99); echo $X mencetak 1. { ...; } jalan di shell yang sama, perubahannya bertahan, dan butuh spasi setelah { serta titik koma sebelum }. $( ... ) mengambil output perintah jadi teks. <( ... ) memberi output perintah sebagai nama file (/dev/fd/63), misalnya comm -12 <(sort a.txt) <(sort b.txt) untuk baris yang ada di keduanya, atau diff <(sort a) <(sort b). Tiap bagian pipe juga subshell, jadi ... | read X gak mengubah X.

Yang akan kamu pelajari