Apa perbedaan dari -a dan -e dalam ekspresi kondisional bash?


12

Dari man bash:

CONDITIONAL EXPRESSIONS
[...]
       -a file
              True if file exists.
[...]
       -e file
              True if file exists.
  1. Jadi apa perbedaan antara [ -a $FILE ]dan [ -e $FILE ], jika ada?
  2. Jika tidak ada perbedaan nyata, mengapa ada dua bendera untuk tujuan yang sama?

Hanya pengembang yang akan tahu # 2 --- kecuali mereka membagikan alasan mereka kepada komunitas.
Belmin Fernandez

Jawaban:


13

Di bash, dengan konteks testperintah dua argumen , -a filedan -e filesama. Tetapi mereka memiliki beberapa perbedaan, karena -ajuga merupakan operator biner.

-eunary didefinisikan oleh POSIX, tetapi -aunary tidak. POSIX hanya mendefinisikan -abiner (Lihat tes POSIX).

POSIX mendefinisikan tiga testperilaku argumen :

3 argumen:

  • Jika $ 2 adalah biner primer, lakukan uji biner $ 1 dan $ 3.

  • Jika $ 1 adalah '!', Negasikan uji dua argumen dari $ 2 dan $ 3.

  • Jika $ 1 adalah '(' dan $ 3 adalah ')', lakukan tes unary sebesar $ 2. Pada sistem yang tidak mendukung opsi XSI, hasilnya tidak ditentukan jika $ 1 adalah '(' dan $ 3 adalah ')'.

  • Kalau tidak, hasilkan tidak ditentukan.

Demikian -ajuga mengarah pada hasil yang aneh:

$ [ ! -a . ] && echo true
true

-adianggap sebagai operator biner dalam konteks tiga argumen. Lihat Bash FAQ pertanyaan E1 . POSIX juga menyebutkan bahwa -adapatkan dari KornShell tetapi kemudian diubah menjadi -ekarena membuat membingungkan antara -abiner dan -aunary.

-E primer, yang memiliki fungsi serupa dengan yang disediakan oleh shell C, ditambahkan karena ia memberikan satu-satunya cara bagi skrip shell untuk mengetahui apakah ada file tanpa mencoba membuka file tersebut. Karena implementasi diizinkan untuk menambahkan jenis file tambahan, skrip portabel tidak dapat menggunakan:

uji -b foo -o -c foo -o -d foo -o -f foo -o -p foo

untuk mengetahui apakah foo adalah file yang ada. Pada sistem BSD historis, keberadaan file dapat ditentukan oleh:

test -f foo -o -d foo

tetapi tidak ada cara mudah untuk menentukan bahwa file yang ada adalah file biasa. Proposal awal menggunakan KornShell -a primer (dengan makna yang sama), tetapi ini diubah menjadi -e karena ada kekhawatiran tentang probabilitas tinggi manusia membingungkan -a primer dengan -a operator biner.

-abiner juga ditandai sebagai usang, karena mengarah ke beberapa ekspresi ambigu, yang memiliki lebih dari 4 argumen. Dengan> 4 argumen argumen ini, POSIX mendefinisikan hasilnya tidak ditentukan.


Keren tahu! Sekarang sedikit lebih jelas :)!
Polym

9

.1. Jadi apa perbedaan antara [-a $ FILE] dan [-e $ FILE], jika ada?

Tidak ada perbedaan sama sekali.

Sejalan 505-507di test.cversi pesta 4.2.45(1)-release:

case 'a':           /* file exists in the file system? */
case 'e':
  return (sh_stat (arg, &stat_buf) == 0);

Itu menunjukkan bahwa tidak ada perbedaan nyata antara kedua bendera.

.2. Jika tidak ada perbedaan nyata, mengapa ada dua bendera untuk tujuan yang sama?

Lihat jawaban gnouc .


3
Di sisi lain, mengingat bahwa -aini juga operator boolean (dan) di bash, tampaknya bug rawan untuk menambahkan makna tambahan yang benar-benar berlebihan; Saya kira itu lebih terkait dengan kompatibilitas dengan beberapa implementasi lain dan / atau kompatibilitas dengan versi sebelumnya yang tidak memiliki -e.
celtschk

@celtschk - itu tidak bugprone, tapi parser shell mungkin. POSIX menentukan -adan -obooleans untuk [ test ]. Tetapi beberapa cangkang (seperti bash) mengisap membedakan argumen dari operator dan [ test ]hasilnya tidak dapat diandalkan. Sejak saat itu POSIX telah mewajibkan bahwa setiap shell yang sesuai menangani setidaknya 4 argumen dalam [ test ]tanda kurung.
mikeserv

5

Jawaban terbaik yang saya temukan adalah ini, dari pertanyaan StackOverflow:

-asudah usang, sehingga tidak terdaftar di halaman manual /usr/bin/testlagi, tetapi masih dalam satu untuk bash. Gunakan -e. Untuk single '[', bash builtin berperilaku sama dengan testbash builtin, yang berperilaku sama dengan /usr/bin/[dan /usr/bin/test (yang satu adalah symlink ke yang lain). Perhatikan efek -atergantung pada posisinya: Jika pada awalnya, artinya file exists. Jika di tengah dua ekspresi, itu berarti logis and.

[ ! -a /path ] && echo existstidak berfungsi, seperti yang ditunjukkan bash manual yang -adianggap sebagai operator biner di sana, dan karenanya di atas tidak diuraikan sebagai negate -a ..tetapi sebagai if '!' and '/path' is true(non-kosong). Jadi, skrip Anda selalu menampilkan "-a"(yang sebenarnya menguji file), dan "! -a"yang sebenarnya adalah biner di andsini.

Karena [[, -atidak digunakan sebagai biner andlagi ( &&digunakan di sana), jadi tujuan uniknya adalah untuk memeriksa file di sana (meskipun sudah usang). Jadi, negasi sebenarnya melakukan apa yang Anda harapkan.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.