Apa tujuan dari suatu perintah yang tidak melakukan apa-apa, hanya sebagai pemimpin komentar, tetapi sebenarnya adalah sebuah shell yang dibangun di dalam dan dari dirinya sendiri?
Ini lebih lambat daripada memasukkan komentar ke dalam skrip Anda sekitar 40% per panggilan, yang mungkin sangat bervariasi tergantung pada ukuran komentar. Satu-satunya alasan yang mungkin bisa saya lihat adalah:
# poor man's delay function
for ((x=0;x<100000;++x)) ; do : ; done
# inserting comments into string of commands
command ; command ; : we need a comment in here for some reason ; command
# an alias for `true' (lazy programming)
while : ; do command ; done
Saya kira apa yang sebenarnya saya cari adalah aplikasi historis apa yang mungkin dimilikinya.
Jawaban:
Secara historis , cangkang Bourne tidak memiliki
true
danfalse
sebagai perintah bawaan.true
bukan hanya alias:
, danfalse
untuk sesuatu sepertilet 0
.:
sedikit lebih baik daripadatrue
untuk portabilitas ke shell yang diturunkan dari Bourne kuno. Sebagai contoh sederhana, pertimbangkan untuk tidak memiliki!
operator pipa atau||
operator daftar (seperti halnya beberapa cangkang Bourne kuno). Ini meninggalkanelse
klausaif
pernyataan sebagai satu-satunya cara untuk bercabang berdasarkan status keluar:Karena
if
memerlukanthen
klausa non-kosong dan komentar tidak dihitung sebagai non-kosong,:
berfungsi sebagai larangan.Saat ini (yaitu: dalam konteks modern) Anda biasanya dapat menggunakan salah satu
:
atautrue
. Keduanya ditentukan oleh POSIX, dan beberapa menemukantrue
lebih mudah dibaca. Namun ada satu perbedaan yang menarik::
adalah yang disebut POSIX khusus built-in , sedangkantrue
adalah biasa built-in .Dibangun khusus harus dibangun ke dalam shell; Built-in biasa hanya "biasanya" built-in, tetapi tidak dijamin sepenuhnya. Seharusnya tidak ada program reguler yang dinamai
:
dengan fungsitrue
di PATH dari kebanyakan sistem.Mungkin perbedaan yang paling penting adalah bahwa dengan built-in khusus, variabel apa pun yang ditetapkan oleh built-in - bahkan di lingkungan selama evaluasi perintah sederhana - tetap ada setelah perintah selesai, seperti yang ditunjukkan di sini menggunakan ksh93:
Perhatikan bahwa Zsh mengabaikan persyaratan ini, seperti halnya GNU Bash kecuali ketika beroperasi dalam mode kompatibilitas POSIX, tetapi semua shell "POSIX sh turunan" utama lainnya mengamati ini termasuk dash, ksh93, dan mksh.
Perbedaan lainnya adalah built-in reguler harus kompatibel dengan
exec
- ditunjukkan di sini menggunakan Bash:POSIX juga secara eksplisit mencatat bahwa
:
mungkin lebih cepat daripadatrue
, meskipun ini tentu saja detail implementasi khusus.sumber
exec
?true
adalah builtin biasa, tapi dia salah dalamexec
menggunakan/bin/true
bukannya builtin.: ${var?not initialized}
et al.:
adalah built-in khusus dan seharusnya tidak memiliki fungsi yang dinamai olehnya. Tapi bukankah contoh yang paling umum terlihat dari fork bomb:(){ :|: & };:
penamaan fungsi dengan nama:
?Saya menggunakannya untuk dengan mudah mengaktifkan / menonaktifkan perintah variabel:
Jadi
Ini membuat skrip bersih. Ini tidak dapat dilakukan dengan '#'.
Juga,
adalah salah satu cara paling sederhana untuk menjamin bahwa 'afile' ada tetapi panjangnya 0.
sumber
>afile
bahkan lebih sederhana dan mencapai efek yang sama.vecho=":"
? Hanya untuk keterbacaan?Aplikasi yang berguna untuk: adalah jika Anda hanya tertarik menggunakan ekspansi parameter untuk efek sampingnya daripada benar-benar meneruskan hasilnya ke perintah. Dalam hal ini Anda menggunakan PE sebagai argumen untuk: atau salah tergantung pada apakah Anda ingin status keluar dari 0 atau 1. Contoh mungkin
: "${var:=$1}"
. Karena:
builtin itu harus cukup cepat.sumber
: $((a += 1))
(++
dan--
operator tidak perlu diimplementasikan sesuai dengan POSIX.). Dalam bash, ksh, dan kemungkinan shell lain yang dapat Anda lakukan juga:((a += 1))
atau((a++))
tetapi tidak ditentukan oleh POSIX.(())
ditentukan sebagai fitur opsional. "Jika urutan karakter yang dimulai dengan" (("akan diuraikan oleh shell sebagai ekspansi aritmatika jika didahului oleh '$', shell yang menerapkan ekstensi dengan mana" ((ekspresi)) "dievaluasi sebagai ekspresi aritmatika dapat memperlakukan "((" sebagai pengantar evaluasi aritmatika alih-alih perintah pengelompokan. ":
bisa juga untuk komentar blok (mirip dengan / * * / dalam bahasa C). Misalnya, jika Anda ingin melewatkan satu blok kode dalam skrip Anda, Anda bisa melakukan ini:sumber
\
melarikan diri salah satu karakter pembatas untuk efek yang sama:: <<\SKIP
.Jika Anda ingin memotong file ke nol byte, berguna untuk menghapus log, coba ini:
sumber
> file.log
lebih sederhana dan mencapai efek yang sama.:>
lebih portabel. Beberapa cangkang (seperti sayazsh
) secara otomatis-instantiate kucing di cangkang saat ini dan dengarkan stdin ketika diberi arahan ulang tanpa perintah. Alih-alihcat /dev/null
,:
jauh lebih sederhana. Seringkali perilaku ini berbeda di shell interaktif daripada skrip, tetapi jika Anda menulis skrip dengan cara yang juga berfungsi interaktif, debug dengan copy-paste jauh lebih mudah.: > file
perbedaan daritrue > file
(selain dari jumlah karakter dan wajah bahagia) di shell modern (dengan asumsi:
dantrue
sama-sama cepat)?Ini mirip dengan
pass
di Python.Satu kegunaannya adalah untuk mematikan fungsi sampai ditulis:
sumber
Dua kegunaan lain yang tidak disebutkan dalam jawaban lain:
Penebangan
Ambil contoh skrip ini:
Baris pertama
set -x
,, membuat shell mencetak perintah sebelum menjalankannya. Ini konstruksi yang cukup berguna. Kelemahannya adalah bahwaecho Log message
jenis pernyataan yang biasa sekarang mencetak pesan dua kali. Metode usus besar mengatasinya. Perhatikan bahwa Anda masih harus keluar dari karakter khusus seperti yang Anda inginkanecho
.Judul pekerjaan cron
Saya telah melihatnya digunakan dalam pekerjaan cron, seperti ini:
Ini adalah tugas cron yang menjalankan skrip
/opt/backup.sh
setiap hari pada pukul 10:45. Keuntungan dari teknik ini adalah membuat subjek email menjadi lebih baik ketika/opt/backup.sh
mencetak beberapa output.sumber
set -x
, perintah yang dicetak (termasuk sesuatu seperti: foobar
) pergi ke stderr.Anda bisa menggunakannya bersamaan dengan backticks (
``
) untuk menjalankan perintah tanpa menampilkan hasilnya, seperti ini:Tentu saja Anda bisa melakukannya
some_command > /dev/null
, tetapi versi:
-agak lebih pendek.Yang sedang berkata saya tidak akan merekomendasikan benar-benar melakukan itu karena hanya akan membingungkan orang. Itu hanya terlintas dalam pikiran sebagai kemungkinan penggunaan.
sumber
Ini juga berguna untuk program polyglot:
Ini sekarang kedua shell-script dieksekusi dan program JavaScript: berarti
./filename.js
,sh filename.js
dannode filename.js
semua pekerjaan.(Jelas sedikit penggunaan yang aneh, tetapi tetap efektif.)
Beberapa penjelasan, seperti yang diminta:
Skrip shell dievaluasi baris demi baris; dan
exec
perintah, saat dijalankan, mengakhiri shell dan menggantikan prosesnya dengan perintah yang dihasilkan. Ini berarti bahwa untuk shell, programnya terlihat seperti ini:Selama tidak ada perluasan parameter atau aliasing yang terjadi dalam kata, setiap kata dalam skrip shell dapat dibungkus dengan tanda kutip tanpa mengubah artinya; ini artinya
':'
setara dengan:
(kami hanya membungkusnya dengan tanda kutip di sini untuk mencapai semantik JavaScript yang dijelaskan di bawah)... dan seperti dijelaskan di atas, perintah pertama pada baris pertama adalah no-op (artinya diterjemahkan
: //
, atau jika Anda lebih suka mengutip kata-kata':' '//'
,. Perhatikan bahwa//
tidak ada arti khusus di sini, seperti halnya dalam JavaScript; itu hanya kata yang tidak berarti yang dibuang.)Akhirnya, perintah kedua pada baris pertama (setelah titik koma), adalah daging asli dari program: itu adalah
exec
panggilan yang menggantikan skrip shell yang dipanggil , dengan proses Node.js dipanggil untuk mengevaluasi sisa skrip.Sementara itu, baris pertama, dalam JavaScript, diurai sebagai string-literal (
':'
), dan kemudian komentar, yang dihapus; dengan demikian, untuk JavaScript, programnya terlihat seperti ini:Karena string-literal berada pada sebuah baris dengan sendirinya, itu adalah pernyataan no-op, dan dengan demikian dilucuti dari program; itu berarti bahwa seluruh baris dihapus, hanya menyisakan kode program Anda (dalam contoh ini,
function(){ ... }
tubuh.)sumber
: //;
dan~function(){}
lakukan? Terima kasih:)
~function(){}
, itu sedikit lebih rumit. Ada sebuah beberapa jawaban lain di sini sentuhan pada itu, meskipun tidak satupun dari mereka benar-benar menjelaskannya untuk kepuasan saya ... jika tak satu pun dari pertanyaan-pertanyaan menjelaskan dengan baik-cukup untuk Anda, jangan ragu untuk posting sebagai pertanyaan di sini, saya akan senang menjawab secara mendalam tentang pertanyaan baru.node
. Jadi bagian fungsinya adalah tentang javascript! Saya baik-baik saja dengan operator unary di depan IIFE. Saya pikir ini terlalu bash di tempat pertama dan sebenarnya tidak benar-benar mendapatkan arti dari posting Anda. Saya baik-baik saja sekarang, terima kasih atas waktu yang Anda habiskan untuk menambahkan «kerusakan»!~{ No problem. (= }
Fungsi mendokumentasikan diri
Anda juga dapat menggunakan
:
untuk menanamkan dokumentasi dalam suatu fungsi.Asumsikan Anda memiliki skrip perpustakaan
mylib.sh
, menyediakan berbagai fungsi. Anda bisa sumber perpustakaan (. mylib.sh
) dan memanggil fungsi langsung setelah itu (lib_function1 arg1 arg2
), atau menghindari mengacaukan namespace Anda dan memohon perpustakaan dengan argumen fungsi (mylib.sh lib_function1 arg1 arg2
).Bukankah lebih baik jika Anda juga bisa mengetik
mylib.sh --help
dan mendapatkan daftar fungsi yang tersedia dan penggunaannya, tanpa harus secara manual mempertahankan daftar fungsi dalam teks bantuan?Beberapa komentar tentang kode:
declare -f
untuk menghitung semua fungsi yang tersedia, kemudian menyaringnya melalui sed untuk hanya menampilkan fungsi dengan awalan yang sesuai.mylib.sh function1
dan diterjemahkan secara internallib_function1
. Ini adalah latihan yang tersisa untuk pembaca.$1
. Pada saat yang sama, itu akan mengacaukan namespace Anda jika Anda sumber perpustakaan. Jika Anda tidak suka itu, Anda dapat mengubah nama menjadi sesuatu sepertilib_help
atau benar-benar memeriksa args--help
dalam kode utama dan memanggil fungsi bantuan secara manual.sumber
Saya melihat penggunaan ini dalam skrip dan berpikir itu adalah pengganti yang baik untuk memanggil nama dalam skrip.
... ini adalah pengganti kode:
basetool=$(basename $0)
sumber
basetool=${0##*/}