Dalam skrip bash, gunakan kondisional "atau" dalam pernyataan "jika"

129

Pertanyaan ini adalah sekuel dari pertanyaan saya sebelumnya . Para pengguna di situs ini dengan baik hati membantu saya menentukan cara menulis bash forloop yang diulang pada nilai string. Sebagai contoh, misalkan variabel kontrol loop fnameberulang di atas string "a.txt" "b.txt" "c.txt". Saya ingin echo"ya!" kapan fnamememiliki nilai "a.txt"atau "c.txt", dan echo"tidak!" jika tidak. Saya telah mencoba skrip bash shell berikut:

#!/bin/bash

for fname in "a.txt" "b.txt" "c.txt"
do
 echo $fname
 if [ "$fname" = "a.txt" ] | [ "$fname" = "c.txt" ]; then
 echo "yes!"
else
 echo "no!"
fi
done

Saya mendapatkan output:

a.txt

tidak!

b.txt

tidak!

c.txt

Iya!

Mengapa ifpernyataan itu ternyata menghasilkan kebenaran ketika fnamememiliki nilai "a.txt"? Apakah saya |salah menggunakan ?

Andrew
sumber
3
Dalam bash, 'atau' operator adalah '||' (Gaya C).
Marius Cotofana
3
Anda juga dapat menggunakan -odalam yang sama [ ].
Thor
6
@Thor saya lebih suka ||dan memisahkan [ ]lebih -ountuk portabilitas hanya karena [tidak dijamin untuk mendukung lebih dari 4 argumen. Tentu saja jika bahasa target bash, tidak ada yang harus menggunakan [lagian karena bash's [[lebih unggul dalam banyak hal.
jw013
2
@ jw013 Terima kasih. Apakah ini berarti saya harus menggunakan if [[ "$fname" = "a.txt" ]] || [[ "$fname" = "c.txt" ]]daripada if [ "$fname" = "a.txt" ] || [ "$fname" = "c.txt" ]?
Andrew
5
@ Andrew Itu benar, jika saat Anda mendeklarasikan shebang sebagai bash, seperti yang sudah Anda lakukan. Salah satu keuntungan [[adalah tidak melakukan pemisahan kata (case khusus) sehingga [[ $unquoted_var = string ]]aman.
jw013

Jawaban:

229

Jika Anda ingin mengatakan ORgunakan pipa ganda ( ||).

if [ "$fname" = "a.txt" ] || [ "$fname" = "c.txt" ]

(Kode OP asli yang digunakan |adalah hanya menyalurkan output dari sisi kiri ke sisi kanan, dengan cara yang sama seperti pipa biasa bekerja.)

bahamat
sumber
4
Selain itu, ||tidak melakukan logika standar "ATAU" - itu sirkuit pendek, dan perintah kedua dijalankan hanya jika yang pertama gagal.
holdenweb
13
@ holdenweb Saya cukup yakin sebagian besar bahasa yang dioptimalkan modern bekerja dengan cara yang sama. Tidak perlu menghabiskan siklus CPU mengevaluasi kondisi kedua ORjika kondisi pertama bernilai true.
bahamat
1
Saya pikir bash suka ==tetapi setelah melihat jawaban ini, saya memutuskan untuk mencarinya. Rupanya, "itu dapat digunakan tetapi tidak standar". Saya pikir saya akan meletakkan ini di sini untuk orang lain jika Anda penasaran: stackoverflow.com/a/2237103
harperville
Ini adalah apa yang testdirekomendasikan halaman manual juga
cdosborn
2
Anda juga dapat menggunakan tes braket ganda - if [[ "$fname" = "a.txt" ]] || [[ "$fname" = "c.txt" ]](Jika Anda ingin atau perlu memiliki fungsi tambahan yang terkait dengannya [[ ]]).
HankCa