Skenario klasik dengan Operator Precedence, Anda memiliki garis seperti:
(cd ~/screenshots/ && ls screenshot* | head -n 5)
Dan Anda tidak tahu apakah itu diuraikan ((A && B) | C)
atau (A && B | C)
...
The dokumentasi hampir resmi ditemukan di sini tidak mencantumkan pipa dalam daftar jadi saya tidak bisa hanya memeriksa di meja.
Selanjutnya dalam bash, (
tidak hanya untuk mengubah urutan operasi tetapi membuat subkulit , jadi saya tidak 100% yakin baris ini setara dengan baris sebelumnya:
((cd ~/screenshots/ && ls screenshot*) | head -n 5)
Lebih umum, bagaimana cara mengetahui AST dari bash line? Dalam python saya memiliki fungsi yang memberi saya pohon sehingga saya dapat dengan mudah memeriksa urutan operasi.
|
itu hanya konektor yang sesuai dengan stdout LHS ke stdin RHS. Jadi, jikacd
perintah dalam contoh Anda gagal, itu tidak akan mengirim output kehead
, tetapihead
pada kenyataannya akan tetapexecute
, mengurai apa-apa, dan mengembalikan tidak ada output.bash
menggunakan parser yacc bukan hal ad-hoc; jika Anda menjalankannya,yacc -v
itu akan memberi Anday.output
tata bahasa yang bagus yang menunjukkan itu&&
dan||
menggabungkan daftar, dan daftar pada akhirnya terdiri dari jaringan pipa (dan bukan sebaliknya); tl; dr;A && B | C
sama denganA && { B | C; }
, seperti yang diharapkan. Jangan menganggap urutan eksekusi antaraB
danC
; perintah-perintah dalam sebuah pipa dijalankan secara paralel .[...]
pengujian dan$((...))
evaluasi aritmatika; khususnya,||
dan&&
seperti yang digunakan dengan daftar perintah dalam bahasa shell memiliki prioritas yang sama , tidak seperti masing-masing operator diC
atau dalam evaluasi aritmatika (di mana&&
mengikat lebih erat daripada||
).Jawaban:
Ini setara dengan
( kelompok kawat gigi perintah bersama tanpa subkulit ). Diutamakan
|
dengan demikian lebih tinggi (mengikat lebih ketat) daripada&&
dan||
. Itu adalah,dan
selalu berarti bahwa output saja B adalah untuk diberikan kepada C . Anda dapat menggunakan
(...)
atau{ ... ; }
untuk menggabungkan perintah bersama sebagai satu kesatuan untuk disambiguasi jika perlu:Anda dapat menguji ini menggunakan beberapa perintah yang berbeda. Jika Anda berlari
maka kamu akan mendapatkan
kembali:
tr a-z A-Z
huruf besar inputnya , dan Anda dapat melihat bahwa hanyaecho world
disalurkan ke dalamnya, sementaraecho hello
melalui sendiri.Ini adalah didefinisikan dalam shell tata bahasa , meskipun tidak sangat jelas: yang
and_or
produksi (untuk&&
/||
) didefinisikan memiliki aapipeline
di tubuhnya, sementarapipeline
hanya berisicommand
, yang tidak mengandungand_or
- hanyacomplete_command
produksi dapat mencapaiand_or
, dan hanya ada di tingkat atas dan di dalam tubuh konstruksi struktural seperti fungsi dan loop.Anda bisa secara manual menerapkan tata bahasa itu untuk mendapatkan parse tree untuk suatu perintah, tetapi Bash tidak menyediakan apa pun itu sendiri. Saya tidak tahu ada shell yang melebihi apa yang digunakan untuk parsing mereka sendiri.
Tata bahasa shell memiliki banyak kasus khusus yang hanya didefinisikan secara semi-formal dan ini bisa menjadi misi yang harus diselesaikan. Bahkan Bash sendiri terkadang salah , sehingga kepraktisan dan cita-cita mungkin berbeda.
Ada parser eksternal yang mencoba mencocokkan sintaks dan menghasilkan pohon, dan dari mereka saya akan merekomendasikan secara luas Morbig , yang mencoba menjadi yang paling dapat diandalkan.
sumber
TL; DR : daftar pemisah seperti
;
.&
,&&
dan||
tentukan urutan penguraian.The bash manual memberitahu kita:
Atau bagaimana wiki Bash Hacker menjelaskannya dengan ringkas
Dengan demikian,
cd ~/screenshots/ && ls screenshot* | head -n 5
ada satu pipa -ls screenshot* | head -n 5
dan satu perintah sederhanacd ~/screenshots/
. Perhatikan bahwa sesuai dengan manualDi sisi lain,
(cd ~/screenshots/ && ls screenshot*) | head -n 5
berbeda - Anda memiliki satu pipa: di sebelah kiri ada subkulit dan di sebelah kanan Anda milikihead -n 5
. Dalam hal ini, menggunakan notasi OP itu(A && B) | C
Mari kita ambil contoh lain:
Di sini kita punya satu daftar
<pipeline1> && <pipeline2>
. Karena kita tahu bahwa status keluar dari pipa sama dengan perintah terakhir danfalse
mengembalikan status negatif alias gagal,&&
tidak akan menjalankan sisi kanan.Di sini pipa kiri memiliki status keluar yang sukses, jadi pipa kanan dieksekusi dan kami melihat hasilnya.
Perhatikan bahwa tata bahasa shell tidak menyiratkan urutan eksekusi aktual. Mengutip salah satu jawaban Gilles :
Dan dari bash manual:
Berdasarkan bahwa dalam
cd ~/screenshots/ && ls screenshot* | head -n 5
yangcd ~/screenshots/
akan dieksekusi pertama,ls screenshot* | head -n 5
jika perintah sebelumnya berhasil, tapihead -n 5
mungkin menjadi proses yang pertama melahirkan bukanls
karena mereka berada dalam pipa.sumber
cd ~/screenshots/ && ls screenshot*
atauhead -n 5
" Yah, ya, itu masalahnya((cd ~/screenshots/ && ls screenshot*) | head -n 5)
. Tapi itu tidak mengatakan apa-apa tentang kasus ambigucd ~/screenshots/ && ls screenshot* | head -n 5
yang tampaknya menjadi titik pertanyaan (dengan atau tanpa tanda kurung di sekitarnya).cd ~/screenshots/ && ls screenshot*
harus diproses terlebih dahulu karena&&
daftar lebih tinggi berdasarkan urutan prioritas (berdasarkan pada jawaban l0b0, setidaknya). Menurut Anda di mana saya harus meningkatkan jawabannya?(cd && ls | head)
dan((cd && ls) | head)
, mungkin baik untuk secara eksplisit tentang yang Anda maksud.Di sinilah ditentukan
bash(1)
:Jadi,
&&
pisahkan jalur pipa.sumber
Anda bisa mencobanya
echo hello && echo world | less
. Anda akan melihat bahwa|
memiliki prioritas lebih tinggi (Sebuah pipa perintah adalah perintah). Ada untuk contoh 2 Anda TIDAK sama. Namun karenacd
tidak memiliki output, Anda tidak akan melihat perbedaan, dengan cara lain.sumber