Sinov yoki [yoki [bash kabukları orasida va boshqa kabuklar orasida ham portativ bormi?

Men qila olaman deb o'ylayman

$ [ -w /home/durrantm ] && echo "writable"
writable

yoki

$ test -w /home/durrantm && echo "writable"
writable

yoki

$ [[ -w /home/durrantm ]] && echo "writable"
writable

I like using the third syntax. Are they equivalent in all ways and fyoki all negative and edge cases? Are there any differences in pyokitability, e.g. between bash on Ubuntu and on OS X yoki older/newer bash versions, e.g. befyokie/after 4.0 and do they both expand expressions the same way?

42
[...] va boshqalar [[...]] va boshqalar test ... uchun bu asosda takroriy savol .
qo'shib qo'ydi muallif Valters Vingolds, manba
Faylning yozuvchanligini tekshirish uchun muayyan masala uchun, shuningdek, Faylga yozish uchun ruxsatni qanday qilib invaziv tarzda sinab ko'rish mumkin?/a>
qo'shib qo'ydi muallif G-Man, manba
"Portativ kod yo'q, faqat portni ko'chirib olgan" degan so'z bor. Bunga oid maslahatim: Eng ko'p o'qiladigan shakldan foydalaning (ehtimol [[...]]) va uni qo'llab-quvvatlaydigan barcha platformalarda sinab ko'ring. Skriptlarni yashirishda juda ko'p narsa yo'q, shuning uchun ular sizning ham, maqsadli auditoriyadan ham foydalanmaydigan qadimgi platformalarda ishlaydi. Bu sizning kodingizni o'qishni qiyinlashtiradi, keraksiz xatolar va ehtimol xavfsizlik muammosini (masalan, ochilish uchun) kiritadi.
qo'shib qo'ydi muallif Sam Gamoran, manba

7 javoblar

Ha, farqlar bor. Eng ko'chma: test yoki [] . Ular POSIX test xususiyatlarining a>.

if ... fi tuzilishi, shuningdek, tomonidan belgilangan. POSIX va to'liq ko'chma bo'lishi kerak.

[[]] bash ( barcha zamonaviylar ) , zsh da va ehtimol boshqalarda, lekin sh yoki dash yoki boshqa oddiy kabuklarda mavjud emas.

Shunday qilib, skriptlarni portativ qilish uchun [] dan foydalaning agar test .

34
qo'shib qo'ydi
$ fayli [ [[f $ fayli]]] hodisasi [[ kodi> bo'sh joy belgilarini o'z ichiga oladi.
qo'shib qo'ydi muallif Matt Enright, manba
@helpermethod da, oddiy ifodalar yasadi [[$ a = ~ ^ reg. * exp. * $ ']]
qo'shib qo'ydi muallif GnP, manba
Faqat bash va zsh ni qo'llab-quvvatlash uchun [[] juda uzoq vaqt ( bash ) 90-yillarning oxiri, zsh 2000 dan ortiq bo'lmagan va hech qachon qo'llab-quvvatlanmagan bo'lsa ajablanaman), shuning uchun [[]. Boshqa POSIX-mos qobiqni (masalan, dash ) uchratish juda ham mumkin.
qo'shib qo'ydi muallif Luke Smith, manba

[ is synonym of the test command and it is simultaneously a bash builtin and separate command. But [[ is a bash keyword and works in some versions only. So for reasons of portability you are better off using single [] or test

[ -w "/home/durrantm" ] && echo "writable"
28
qo'shib qo'ydi

Please note, that [] && cmd Xuddi shunday emasif .. fi construction.

Sometimes its behaviour its pretty similar and you can use [] && cmd instead of if .. fi. But only sometimes. If you have more then one command to execute if condition or you need if .. else .. fi be careful and whatch the logic.

Bir necha misol:

[ -z "$VAR" ] && ls file || echo wiiii

Xuddi shunday emas

if [ -z $VAR ] ; then
  ls file
else
  echo wiii
fi

chunki ls muvaffaqiyatsiz bo`lsa if bilan bo`lmaydigan kod amalga oshiriladi.

Yana bir misol:

[ -z "$VAR" ] && ls file && echo wiii

Xuddi shunday emas

if [ -z "$VAR" ] ; then
   ls file
   echo $wiii
fi

ammo bu qurilish bir xil bo'ladi

[ -z "$VAR" ] && { ls file ; echo wiii ; }

echo muhim va u erda bo'lishi kerak bo'lganidan keyin ; ga e'tibor bering.

Shunday qilib, yuqorida keltirilgan bayonnomani yuqorida aytib o'tamiz

[] && cmd == if first command is successful then execute the next one

if .. fi == if condition (which may be the test command as well) then execute command(s)

Shuning uchun [ va [[] faqat [] dan foydalaning.

if is POSIX compatible. So if you have to choose between [ and if choose looking at your task and expected behaviour.

19
qo'shib qo'ydi
Men a) bu asosan yaxshi javob, chunki u har xil savolga javob. b) subtitut sifatida [ va agar ni taqdim qilsangiz, lekin ular mavjud emas. Bu agar bo'lsa, && kodini o'zgartiradi. [, ba'zi kodni amalga oshiradi va ls kabi holatni qaytaradi va grep bo'ladi. agar bo'lsa filiallar bajarilganidan keyin berilgan buyruqlar (ifodani) ning qaytish holatiga bog'liq holda, bu har qanday buyruq (iboralar) bo'lishi mumkin. && keyingi kodni faqat oldingi 0 kodi, agar oddiygina if..then..fi ga o'xshash bo'lsa, amalga oshiradi.
qo'shib qo'ydi muallif GnP, manba
Siz haqingiz to'g'riligini, u erda tahrir tarixini o'tkazib yubordim. Uzr so'rayman. Aytganimdek, bu asosan yaxshi javob, shuning uchun men ovozimni o'zgartirdim.
qo'shib qo'ydi muallif GnP, manba
Ehtimol, men faqat zich yashayman, lekin farqni qanday ko'rsata olaman ... bu ikkita konstruktsiyaning turli natijalar beradigan misolini keltira olasizmi?
qo'shib qo'ydi muallif evilsoup, manba
@evilsoup, yangilandi. Ehtimol, men eng yaxshi so'zlovchi emasman, lekin umid qilamanki, bu hozir aniq bo'ladi.
qo'shib qo'ydi muallif agrublev, manba
Yaxshi, yaxshi. a) iltimos, Maykldan sharhni tekshiring. Dastlab, boshqa savol paydo bo'lganligi haqida qisqacha tushuntirish mavjud. Men faqat tarix uchun javobni qoldirdim. b) Javob ko'pincha && .. || va if .. else .. fi orasidagi farq haqida edi.
qo'shib qo'ydi muallif agrublev, manba
Savolga [vs va [vs viktorina] haqida ham ma'lumot berilsin, agar ... va boshqalar. Afsuski, bu javobni nuqsonsiz deb hisoblaydi. Savolga kelmaslik uchun kechirimlilik, bu birinchi navbatda bunga sabab bo'ldi. Jonli va o'rganishga harakat qiling. :)
qo'shib qo'ydi muallif ExpelledFromParadise, manba
Juda yaxshi fikrlar, shoshilib. Sizning 1-misolingizning xavfsiz shakli quyidagicha bo'lishi mumkin: [-z "$ YO'Q"] && {ls file; haqiqiy; } || echo wiiii . Bu biroz ko'proq ifodalaydi, lekin u if ... fi qurilishidan ancha qodir.
qo'shib qo'ydi muallif DirkGently, manba

It's actually the && that is replacing the if, not the test: an if statement in shell scripting tests whether a command returned a "successful" (zero) exit status; in your example, the command is [.

Shunday qilib, siz bu erda o'zgarib turadigan ikkita narsa bor: testni ishlatish uchun ishlatiladigan buyruq va ushbu test natijasiga asoslangan holda kodni bajarish uchun ishlatiladigan sintaksik.

Sinov buyruqlar:

  • test is a standardised command for evaluating properties of strings and files; in your example, you are running the command test -w /home/durrantm
  • [ is an alias of that command, equally standardised, which has a mandatory last argument of ] in order to look like a bracketed expression; don't be fooled, it's still just a command (you may even find that your system has a file called /bin/[)
  • [[ is an extended version of the test command built into some shells, but not part of the same POSIX standard; it includes extra options which you are not using here

Shartli iboralar:

  • The && operator (standardised here) performs a logical AND operation, by evaluating two commands and returning 0 (which represents true) if they both return 0; it will only evaluate the second command if the first one returned zero, so it can be used as a simple conditional
  • The if ... then ... fi construct (standardised here) uses the same method of judging "truth", but allows for a compound list of statements in the then clause, rather than the single command afforded by an && short-circuit, and provides elif and else clauses, which are hard to write using only && and ||. Note that there are no brackets around the condition in an if statement.

Shunday qilib, quyida keltirilgan barcha sizning namunangizga o'xshash portativ va to'liq tengdir:

  • test -w /home/durrantm && echo "writable"
  • [ -w /home/durrantm ] && echo "writable"
  • if test -w /home/durrantm; then echo "writable"; fi
  • if [ -w /home/durrantm ]; then echo "writable"; fi

[[: : :

  • [[ -w /home/durrantm ]] && echo "writable"
  • if [[ -w /home/durrantm ]]; then echo "writable"; fi
9
qo'shib qo'ydi
Ha, men bu savolga javob bera olamanmi?
qo'shib qo'ydi muallif ExpelledFromParadise, manba

Bourne kabi dunyodagi portativlikni istasangiz, u holda:

test -w /home/durrantm && echo writable

eng portativ hisoblanadi. Bourne, csh va rc oilalarining qobig'ida ishlaydi.

test -w /home/durrantm && echo "writable"

rc oilasi ( rc , as < writable o'rniga "yoziladigan /code>, akanga , bu erda " maxsus emas).

[ -w /home/durrantm ] && echo writable

$ PATH csh yoki rc kodi> (ayrimlari test [ alias] emas, balki ma'lum.

if [ -w /home/durrantm ]; then echo writabe; fi

faqat Bourne oilasining qobig'ida ishlaydi.

[[ -w /home/durrantm ]] && echo writable

Faqat ksh (kelib chiqadigan joy), zsh va bash (Bourne oilasidagi barcha 3) da ishlaydi.

Hech qaysi kerak bo'lmasa fish qobig'ida ishlamaydi:

[ -w /home/durrantm ]; and echo writable

yoki:

if [ -w /home/durrantm ]; echo writable; end
7
qo'shib qo'ydi

Taşınabilirlik uchun sinov / [] ni ishlating. Lekin agar siz ko'chma ma'lumotga ehtiyoj sezmasangiz, o'zingizning va o'zingizning skriptni o'qigan boshqa kishilarning aqli uchun [[. :)

Shuningdek, testning farqini nima, BashFAQ da [va [[?] ).

7
qo'shib qo'ydi

My most important reason for choosing either if foo; then bar; fi or foo && bar is whether the exit status of the whole command is important.

solishtiring:

#!/bin/sh
set -e
foo && bar
do_baz

bilan:

#!/bin/sh
set -e
if foo; then bar; fi
do_baz

Siz ham xuddi shu narsani qilishingiz mumkin; lekin agar foo ishlamay qolsa (yoki sizning nuqtai nazaringizga qarab, noto'g'ri bo'lsa), birinchi misolda do_baz ijro etilmaydi, chunki skript chiqishi mumkin ... set -e , agar biron-bir buyruq noto'g'ri holatga qaytsa, qobiqning darhol chiqib ketishini bildiradi. Agar siz shunday narsalarni qilsangiz juda foydali:

cd /some/directory
rm -rf *

cd har qanday sabab bilan bajarilmasa, skriptning ishlashni davom ettirishini xohlamaysiz.

0
qo'shib qo'ydi
Hech qanday xato foo har ikki holatda ham skriptni bekor qilmaydi. Bu kod set -e uchun maxsus holatdir (agar buyruq shartli deb baholasa (ba'zi &&/| holatida yoki if/while/until/elsif ... shartlari). bar muvaffaqiyatsiz tugadi, ikkala holatda ham qobiqdan chiqadi.
qo'shib qo'ydi muallif Stéphane Chazelas, manba
Siz cd/some/directory && rm -rf - * yoki cd/some/directory || Chiqish; rm -rf - * (yashirin fayllar hali o'chirilmaydi). Men kodni to'g'ri kod yozishga harakat qilmaslik uchun uz kodi sifatida set -e dan foydalanish fikrini shaxsan yoqtirmayman.
qo'shib qo'ydi muallif Stéphane Chazelas, manba