Menggunakan $? dalam pernyataan if


12
function foo {
   (cd $FOOBAR;
   <some command>
   if [$? -ne 0]
   then
      echo "Nope!"
   else
      echo "OK!"
   fi
   )
}

Saya mencoba menulis fungsi seperti di atas dan meletakkannya di file .bashrc saya. Setelah saya sumber file dan jalankan, saya mendapatkan:

Total waktu: 51 detik
-bash: [1: perintah tidak ditemukan
OK!

Adakah yang bisa membantu saya memahami kesalahan saya?


4
Menguji apakah $?sama dengan 0 dengan ifpernyataan tidak ada gunanya, ifmengharapkan perintah dan jika perintah itu kembali 0, ia menjalankan kode di blok. jadi if true; then echo hello; fiakan menggema halo sejak perintah truekembali 0.
llua

1
@ llua Ini tidak ada gunanya. $?memegang status pipa terakhir , yang bukan perintah test( [) dalam ifpernyataan. Contohnya adalah menguji apakah some commandberhasil. Anda dapat melakukan hal yang sama dengan &&dan ||, tetapi dapat membuat garis yang panjang dan tidak dapat dibaca dibandingkan dengan if [ $? -eq 0 ]. Argumen yang sama berlaku untukif some command
bonsaiviking

@ bonsaiviking Saya sangat menyadari apa yang $?berkembang, saya menunjukkan tidak ada gunanya testdigunakan; karena if some commandmelakukan hal yang sama dengan satu pernyataan versus memiliki dua pernyataan terpisah. jika perintah sudah panjang, menambahkan tiga karakter tidak akan membuat 'tidak terbaca' sangat 'tidak terbaca'.
llua

Jawaban:


33

Tambahkan spasi setelah [, dan yang lain sebelum ]:

function foo {
   (cd $FOOBAR;
   <some command>
   if [ $? -ne 0 ]
   then
      echo "Nope!"
   else
      echo "OK!"
   fi
   )
}

[adalah shell builtin, itu adalah perintah seperti echo, read, expr... perlu spasi setelah, dan membutuhkan pencocokan ].

Menulis [ $? -ne 0 ]sebenarnya memohon [dan memberikan 4 parameter: $?, -ne, 0, dan ].

Catatan: fakta bahwa Anda mendapatkan pesan kesalahan [1: command not foundberarti $?memiliki nilai 1.


1
Saya baru saja memverifikasi bahwa jawaban Anda benar pada VM Linux saya.
samiam

[adalah link ke testserta
Ricky Beam

2
@ RickyBeam di sebagian besar shell, [adalah builtin shell, dan /usr/bin/[jarang digunakan.
Patrick

20

Atau Anda bisa melewati $?semuanya. Jika perintah Anda cmd, berikut ini akan berfungsi:

function foo {
   (cd $FOOBAR;
   if cmd
   then
      echo "OK!"
   else
      echo "Nope!"
   fi
   )
}

6

Ini praktik yang baik untuk menetapkan nilai kembali ke variabel sebelum menggunakannya

retval="$?"
if [ $retval -ne 0 ]

Ini memungkinkan Anda untuk menggunakan kembali nilai pengembalian. misalnya dalam pernyataan if ... elif ... else ....


-1: Anda lupa spasi setelahnya [(Tanpa spasi, itu menjadi kesalahan sintaksis dalam bash) Akan dibatalkan jika Anda mengedit dan memperbaiki kesalahan Anda.
samiam

Yap, kamu benar. Aku telah memperbaikinya.
Abdul

@samiam bahwa komentar terakhir ditujukan kepada Anda
terdon

4
:) Bisakah Anda sedikit memperluas jawaban Anda. Mengapa itu praktik yang baik? Kesalahan apa yang bisa dihindari?
terdon

1
@terdon itu praktik buruk untuk digunakan $?secara langsung karena itu akan rusak jika Anda pernah, ketika mengedit skrip nanti, meletakkan garis antara perintah dan $?cek.
samiam

3

Satu-satunya alasan mengapa Anda ingin menggunakan $?argumen untuk [perintah (apakah [perintah itu dijalankan di bagian kondisi ifpernyataan atau tidak) adalah ketika Anda ingin membedakan status pengembalian tertentu, seperti:

until
  cmd
  [ "$?" -gt 1 ]
do
  something
done

Sintaks untuk semua orang if, while, until... pernyataan adalah

if cmd-list1
then cmd-list2
else cmd-list3
fi

Yang berjalan cmd-list2jika cmd-list1berhasil atau cmd-list3tidak.

The [ "$?" -eq 0 ]perintah adalah no-op. Ini ditetapkan $?ke 0 jika $?adalah 0, dan $?menjadi tidak-nol jika bukan-nol.

Jika Anda ingin menjalankan sesuatu jika cmdgagal, itu:

if ! cmd
then ...
fi

Secara umum, Anda tidak perlu mengutak-atik $?apalagi mengetahui nilai yang berarti trueatau false. Satu-satunya kasus adalah seperti yang saya katakan di atas jika Anda perlu mendiskriminasikan nilai tertentu, atau jika Anda perlu menyimpannya nanti (misalnya mengembalikannya sebagai nilai pengembalian fungsi) seperti:

f() {
  cmd; ret=$?
  some cleanup
  return "$ret"
}

Juga ingat bahwa membiarkan variabel tidak dikutip adalah operator split + glob. Tidak masuk akal untuk memanggil operator itu di sini, jadi seharusnya:

[ "$?" -ne 0 ]

tidak [ $? -ne 0 ], apalagi [$? -ne 0 ](yang hanya akan memanggil [perintah jika $IFSkebetulan mengandung karakter pertama $?).

Perhatikan juga bahwa cara Bourne untuk mendefinisikan suatu fungsi adalah tetap function-name()di depan perintah. Itulah yang terjadi di setiap shell Bourne seperti kecuali bashdan yash(dan versi terbaru posh) yang hanya memungkinkan perintah majemuk (perintah majemuk menjadi {...}atau (...)atau hal-hal seperti for...done, if...fi...

function foo { ... }adalah kshsintaks definisi fungsi. Tidak ada alasan mengapa Anda ingin menggunakannya di sini.

Kode Anda dapat ditulis (POSIXly) dengan mudah:

foo() (
  cd -P -- "$FOOBAR" || return # what if the cd failed!
  if
    <some command>
  then
    echo 'OK!'
  else
    echo 'Nope!'
  fi
)

Perhatikan juga bahwa cdtanpa -Pmemiliki makna yang sangat khusus (menangani jalur yang berisi ..komponen berbeda dari perintah lain), jadi lebih baik untuk memasukkannya ke dalam skrip untuk menghindari kebingungan.

(fungsi itu kembali falsejika cdgagal, tetapi tidak jika <some command>gagal).


1

Saya percaya perintah di bawah ini akan melakukan semua yang Anda inginkan dalam satu baris.

(( verify = $?!=0?'Nope!':'OK!' ))
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.