Misalnya, perintah berikut ini tidak berfungsi:
if [[-e xyz]]; then echo File exists;fi
ksh memberikan kesalahan berikut
[[-e: command not found
Apakah itu karena "[[-" ambigu?
Misalnya, perintah berikut ini tidak berfungsi:
if [[-e xyz]]; then echo File exists;fi
ksh memberikan kesalahan berikut
[[-e: command not found
Apakah itu karena "[[-" ambigu?
Jawaban:
Penjelasan yang paling sederhana adalah, karena dalam manual itu muncul [[ expression ]]
sehingga harus ada ruang antara [[
dan expression
dan penutup ]]
. Tetapi tentu saja kita dapat mencoba untuk melihatnya secara lebih mendalam. Kerang memiliki tata bahasa yang agak rumit dan sangat bergantung pada konsep "pemisahan kata". Secara khusus, ksh (1) menyatakan manual:
Shell mulai mengurai inputnya dengan memecahnya menjadi kata-kata. Kata-kata, yang merupakan urutan karakter, dibatasi oleh karakter spasi putih yang tidak dikutip (spasi, tab, dan baris baru) atau meta-karakter (<,>, |,;, &, (,)). Selain membatasi kata, spasi dan tab diabaikan, sedangkan baris baru biasanya membatasi perintah.
Jadi seperti yang dinyatakan dalam manual, urutan karakter [[-e
dianggap kata shell. ksh
akan mencari perintah seperti itu dalam daftar built-in dan operator khusus (suka for
atau while
), kemudian mencari perintah eksternal - dan voilà - tidak ada yang ditemukan, maka ada pesan kesalahan tentang perintah tidak ditemukan.
Dalam hal ini [[
juga bukan meta-karakter khusus. Jika ya, -e
bagian dalam [[-e
akan dianggap sebagai kata shell, bukan argumen untuk [[
dirinya sendiri. Namun, [[
dijelaskan sebagai perintah majemuk, dan manual mengatakan sebagai berikut:
Perintah majemuk dibuat menggunakan kata-kata yang dicadangkan berikut - kata-kata ini hanya dikenali jika mereka tidak dikutip dan jika digunakan sebagai kata pertama dari suatu perintah (yaitu, mereka tidak dapat didahului oleh penugasan parameter atau pengalihan):
Jadi agar [[
dapat dikenali sebagai perintah majemuk, itu harus menjadi kata pertama dari perintah atau daftar perintah, yang menurut definisi sebelumnya dari "kata" menyiratkan itu harus dipisahkan oleh spasi, tab, atau baris baru dari lainnya kata-kata / argumen.
Anda telah bertanya di komentar : "Mengapa parser tidak bisa berhenti begitu menemukan" [["pola, dan memperlakukan itu sebagai awal dari perintah bersyarat?" Jawaban singkat mungkin karena 1) pengaruh [
sintaksis karena awalnya merupakan perintah eksternal, dan untuk kepatuhan standar POSIX ada sebagai perintah eksternal bahkan hari ini, dan 2) karena parser shell dibangun demikian. Shell parser dapat mengenali karakter khusus yang tidak dibatasi ruang: echo $((2+2))
dan (echo foobar)
berfungsi dengan baik. Mungkin di masa depan ketika ksh
pengembangan dilanjutkan atau tampaknya ada percabangan atau klon (seperti mksh
atau pdksh
) seseorang akan mengimplementasikan sintaksis tanpa spasi di [[-e
.
[[
disebut "kata yang dilindungi undang-undang" (lihat bagian 2.9 dari Bahasa Perintah Shell ). Menurut definisi POSIX, kata yang dipesan harus dibatasi oleh spasi. Sebaliknya (
adalah operator, dan negara standar di bagian 2.9 "representasi termasuk spasi antara token di beberapa tempat di mana <blank>
s tidak diperlukan (ketika salah satu token adalah operator)". Lihat diskusi terkait: POSIX Shell Grammar: Mengapa Brace Group Membutuhkan Ruang Pertama Tapi Subshell Tidak?char
adalah kata kunci tetapi Anda masih tidak dapat menulis charsomeletter = 'A';
dan berharap parser berhenti setelah melihat char
.
i--<=++j
, dan kompiler tidak memiliki masalah menguraikan itu sebagai i -- <= ++ j
.
_
). Ksh memiliki (
sebagai operator , dan (echo hello)
mem - parsing sebagai ( echo hello )
. Ini telah if
, {
, [[
, dan lainnya kata kunci , dan ifx
, {x
, dan [[x
masing-masing satu token - seperti bagaimana charsomeletter
adalah salah satu C tanda. Sebaliknya, tanda kutip (x
dalam ksh adalah dua token - seperti bagaimana i--
dua token dalam C. Apa yang secara konseptual berarti menjadi operator berbeda antara shell gaya Bourne (seperti ksh) dan C. Tapi Peter A. Schneider menunjukkan sebuah kesamaan leksikal nyata .
Yang penting untuk dicatat adalah itu [
adalah perintah, dan kata kunci shell [[
dalam bash dan ksh didasarkan pada [
.
[[
digunakan dalam cara yang mirip dengan [
. Kadang-kadang Anda bahkan dapat mengganti [
]
dengan [[
]]
tanpa perubahan perilaku. Dengan [
, seperti perintah apa pun, spasi wajib antara perintah dan argumennya. Hal yang sama berlaku untuk [[
.
Kami dulu hanya punya /usr/bin/[
. Sekarang sebagian besar shell sudah [
dibangun untuk efisiensi — tetapi sintaksnya sama. Dalam shell yang menyediakan [[
, itu berfungsi sebagai alternatif yang lebih fleksibel[
.
Berikut ini deskripsi untuk [
di bash:
$ help [
[: [ arg... ]
Evaluate conditional expression.
This is a synonym for the "test" builtin, but the last argument must
be a literal `]', to match the opening `['.
Jadi [
sama dengan test
(selain mengharapkan ]
argumen di akhir). help test
akan memberikan detail lebih banyak tentang itu. Anda dapat membandingkan ini dengan help [[
.
Ada juga halaman manual untuk perintah eksternal [
( man \[
).
Dalam kasus
if [[-e
[
juga [[
adalah perintah, ada. Kata lengkapnya [[-e
adalah.if [[-e
membuatnya menjadi ujian untuk benar / salah. Jadi, apakah [[-e
ada perintah ? Apakah itu karena "[[-" ambigu?
Iya. Atau tidak. [[-e
adalah apa adanya: tidak ada yang dipahami shell sehingga ia menganggap itu adalah perintahnya sendiri. ;-)
[[-e
adalah nama perintah yang berpotensi valid (jika terlihat aneh).
Ruang adalah pembatas dan diperlukan. Seperti yang Anda lihat dari shellcheck
:
$ shellcheck gmail-browse-msgs-algorithm.sh
In gmail-browse-msgs-algorithm.sh line 847:
[[$Today != "${DaysArr[ i + DAY_DELETED_ON_NDX ]}" ]] && continue
^-- SC1035: You need a space after the [[ and before the ]].
(Baik ksh dan bash mendukung [[
dan tidak bekerja tanpa spasi. Shellcheck memberikan output yang persis sama dengan skrip ksh dan bash yang berisi baris buggy.)
Mengapa pembatas diperlukan karena token dan leksikon .
ksh
shell dalam pertanyaan. Bash meminjam [[
operator dari ksh
dan dalam pertanyaan ini perilaku mereka identik, tapi saya akan berhati-hati dari asumsi karena ada beberapa perbedaan yang signifikan antara ksh
dan bash
perilaku dan internal. Itu hanya karena shellcheck berfungsi pada skrip bash, mungkin itu bukan alat yang tepat untuk skrip ksh. Hanya sesuatu yang perlu diingat ketika mendekati kerang yang berbeda
[[
aturan bawaan . Saya sama sekali tidak dapat menyimpulkan bahwa ksh
itu adalah shell yang shellcheck
dapat menemukan kesalahan. Saya berharap orang lain menghargai ksh
dan bash
dua penafsir yang berbeda. Terima kasih telah menyebutkannya. Juga patut dicatat [[
adalah bash yang dibangun sementara [
adalah perintah eksternal.
[
juga built-in di bash :) manpages.ubuntu.com/manpages/bionic/man7/bash-builtins.7.html Tapi Anda tidak jauh - [
atau test
diharuskan menjadi perintah eksternal. Pada masa shell Bourne asli [
sebenarnya merupakan perintah eksternal, dan masih ada saat ini /usr/bin/[
karena POSIX mengharuskannya menjadi perintah eksternal pubs.opengroup.org/onlinepubs/009695399/utilities/test.html Sangat sedikit yang diperlukan oleh POSIX untuk menjadi built-in pubs.opengroup.org/onlinepubs/009695399/idx/sbi.html Builtin [
untuk efisiensi
ksh
; menggunakan hashbang atau -s ksh
. Btw, ksh dan bash memiliki [[
"built in," tapi itu kata kunci , tidak seperti [
, yang merupakan builtin shell . (ksh :; whence -v [ [[
bash type [ [[
:) Builtin dan perintah eksternal secara sintaksis sama. Salah satu cara [[
berbeda dari itu [
adalah yang [[
menekan beberapa ekspansi dalam argumennya, yang tidak bisa sebagai builtin - sama seperti {
tidak dapat melakukan pengelompokan jika itu builtin. Ini mungkin mengapa {x
(atau [[x
) menjadi satu token terasa aneh. Saya pikir itu benar untuk mengatakan builtin dan kata kunci secara leksikal tetapi tidak mirip secara sintaksis . @SergiyKolodyazhnyy
[[
bisa menjadi perintah eksternal! Artinya, ini mungkin program dan bukan sintaks yang didukung oleh shell Anda secara langsung. Mendukung sintaksis tanpa spasi mungkin untuk ksh
tetapi akan gagal pada sistem dengan eksternal [[
sehingga untuk alasan kompatibilitas lebih baik untuk menjaga ruang yang diperlukan.
BusyBox menyediakan [[
sebagai perintah eksternal , misalnya.
Karena [[-e
dapat berpartisipasi dalam ekspansi shell (dapat digunakan seperti
echo [[-e]*
untuk membuat daftar semua file yang dimulai dengan huruf di antara [
dan secara e
inklusif), itu akan menjadi kekacauan total jika [
dan ]
merupakan karakter khusus yang tidak berpartisipasi dalam pemisahan kata yang diatur oleh spasi.
[[
adalah kata kunci - mungkin pohon parsing shell mengharuskan kata kunci harus ditentukan oleh spasi