Periksa keberadaan argumen input dalam skrip Bash shell

1340

Saya perlu memeriksa keberadaan argumen input. Saya memiliki skrip berikut

if [ "$1" -gt "-1" ]
  then echo hi
fi

saya mendapat

[: : integer expression expected

Bagaimana cara memeriksa input argumen1 terlebih dahulu untuk melihat apakah ada?

pengguna775187
sumber

Jawaban:

2332

Ini:

if [ $# -eq 0 ]
  then
    echo "No arguments supplied"
fi

The $#variabel akan memberitahu Anda jumlah argumen input script disahkan.

Atau Anda dapat memeriksa apakah argumen adalah string kosong atau tidak suka:

if [ -z "$1" ]
  then
    echo "No argument supplied"
fi

The -zswitch akan menguji apakah perluasan "$ 1" adalah nol string atau tidak. Jika itu adalah string nol maka tubuh dieksekusi.

phoxis
sumber
62
Saya suka melakukannya dengan cara ini, dalam sintaks singkat dan masih POSIX dapat diterima. [ -z "$1" ] && echo "No argument supplied" Saya lebih suka satu kalimat, karena lebih mudah bagi saya; dan itu juga lebih cepat untuk memeriksa nilai keluar, dibandingkan dengan menggunakanif
JM Becker
168
Anda mungkin ingin menambahkan sebuah exit 1di akhir gema Anda di dalam blok if ketika argumen diperlukan agar skrip berfungsi. Jelas, tetapi perlu diperhatikan untuk kelengkapannya.
msanford
16
Dimungkinkan, meskipun jarang bermanfaat, untuk argumen pertama diinisialisasi tetapi kosong; programname "" secondarg third. The $#cek jelas memeriksa jumlah argumen.
tripleee
39
Untuk pemula, terutama seseorang yang berasal dari latar belakang non-scripting, penting juga untuk menyebutkan beberapa kekhasan tentang hal-hal ini. Anda bisa juga menyebutkan bahwa kita membutuhkan ruang setelah pembukaan dan penjepit penutup. Kalau tidak, berbagai hal tidak akan berhasil. Saya sendiri adalah scripting noob (saya berasal dari latar belakang C) dan merasa sulit. Hanya ketika saya memutuskan untuk menyalin seluruh hal "sebagaimana adanya" hal-hal bekerja untuk saya. Saat itulah saya menyadari bahwa saya harus meninggalkan tempat setelah penjepit pembuka dan sebelum penutup.
HighOnMeat
72
dan untuk args opsionalif [ ! -z "$1" ]; then ...
gcb
347

Lebih baik menunjukkan cara ini

if [[ $# -eq 0 ]] ; then
    echo 'some message'
    exit 1
fi

Anda biasanya perlu keluar jika Anda memiliki terlalu sedikit argumen.

Val
sumber
72
Tidak bukan: ini memiliki exit 1yang biasanya Anda inginkan, dan menggunakan [[ ]]tes yang (iirc) biasanya lebih masuk akal. Jadi untuk orang-orang yang secara buta menyalin kode tempel ini adalah jawaban yang lebih baik.
dshepherd
42
Untuk mengetahui lebih lanjut tentang perbedaan antara [] dan [[]] lihat stackoverflow.com/questions/3427872/…
Sebastián Grignoli
104

Dalam beberapa kasus, Anda perlu memeriksa apakah pengguna meneruskan argumen ke skrip dan jika tidak, kembali ke nilai default. Seperti pada skrip di bawah ini:

scale=${2:-1}
emulator @$1 -scale $scale

Di sini jika pengguna belum lulus scalesebagai parameter ke-2, saya meluncurkan emulator Android -scale 1secara default. ${varname:-word}adalah operator ekspansi. Ada juga operator ekspansi lainnya:

  • ${varname:=word}yang menetapkan undefined varnamebukannya mengembalikan wordnilai;
  • ${varname:?message}yang akan kembali varnamejika sudah ditentukan dan bukan nol atau mencetak messagedan membatalkan skrip (seperti contoh pertama);
  • ${varname:+word}yang mengembalikan wordhanya jika varnamedidefinisikan dan bukan nol; mengembalikan nol sebaliknya.
Aleks N.
sumber
1
Contoh di atas sepertinya digunakan ${varname?message}. Apakah tambahan :kesalahan ketik, atau apakah itu mengubah perilaku?
Eki
6
Eki, ":" adalah perintah bawaan dan singkatan untuk / bin / true dalam contoh ini. Ini mewakili perintah do-nothing yang pada dasarnya mengabaikan argumen yang diberikan. Sangat penting dalam tes ini untuk menjaga penerjemah dari mencoba mengeksekusi isi "$ varname" (yang Anda tentu TIDAK ingin terjadi). Juga perlu diperhatikan; Anda dapat menguji banyak variabel dengan metode ini seperti yang Anda inginkan. Dan semua dengan pesan kesalahan tertentu. yaitu: ${1?"First argument is null"} ${2?"Please provide more than 1 argument"}
user.friendly
48

Mencoba:

 #!/bin/bash
 if [ "$#" -eq  "0" ]
   then
     echo "No arguments supplied"
 else
     echo "Hello world"
 fi
Ranjithkumar T
sumber
4
Mengapa Anda perlu tanda kutip ganda untuk $#dan 0?
user13107
1
Tidak masalah jika kita menggunakan tanpa tanda kutip ganda seperti $ # dan 0
Ranjithkumar T
di windows, mingw ini adalah satu-satunya cara untuk pergi.
Lajos Meszaros
2
Jawaban ini memberikan titik awal yang bagus untuk skrip yang baru saya buat. Terima kasih telah menunjukkan else, juga.
Chris K
2
@ user13107 variabel kutip ganda dalam bash mencegah globbing (mis. memperluas nama file seperti foo*) dan pemisahan kata (yaitu membelah konten jika nilainya mengandung spasi). Dalam hal ini tidak perlu mengutip $#karena kedua kasus tersebut tidak berlaku. Mengutip 0juga tidak perlu, tetapi beberapa orang lebih suka mengutip nilai karena mereka benar-benar string dan yang membuatnya lebih eksplisit.
Dennis
39

Cara lain untuk mendeteksi jika argumen dilewatkan ke skrip:

((!$#)) && echo No arguments supplied!

Catatan yang (( expr ))menyebabkan ekspresi dievaluasi sesuai aturan Aritmatika Shell .

Untuk keluar tanpa adanya argumen, orang dapat mengatakan:

((!$#)) && echo No arguments supplied! && exit 1

Cara (analog) lain untuk mengatakan hal di atas adalah:

let $# || echo No arguments supplied

let $# || { echo No arguments supplied; exit 1; }  # Exit if no arguments!

help let mengatakan:

let: let arg [arg ...]

  Evaluate arithmetic expressions.

  ...

  Exit Status:
  If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise.
devnull
sumber
2
-1 ini mungkin metode terburuk jika memvalidasi keberadaan argumen .. ditambah lagi dapat memicu penggantian riwayat dan berpotensi melakukan hal-hal buruk.
user.friendly
2
alih-alih exityang membunuh proses zsh saya, saya menggunakan returnyang tidak membunuhnya
Timo
Mengapa akan ((!$#))memicu substitusi sejarah?
Zhro
25

Saya sering menggunakan potongan ini untuk skrip sederhana:

#!/bin/bash

if [ -z "$1" ]; then
    echo -e "\nPlease call '$0 <argument>' to run this command!\n"
    exit 1
fi
f2cx
sumber
1
Jadi, ini untuk digunakan karena Anda hanya perlu satu argumen?
Danijel
21

Hanya karena ada lebih banyak titik dasar untuk ditunjukkan, saya akan menambahkan bahwa Anda dapat menguji string Anda adalah nol:

if [ "$1" ]; then
  echo yes
else
  echo no
fi

Demikian juga jika Anda mengharapkan penghitungan arg hanya menguji terakhir Anda:

if [ "$3" ]; then
  echo has args correct or not
else
  echo fixme
fi

dan seterusnya dengan arg atau var apa saja

seorphate
sumber
4

Jika Anda ingin memeriksa apakah argumen tersebut ada, Anda dapat memeriksa apakah # argumen lebih besar atau sama dengan jumlah argumen target Anda.

Script berikut menunjukkan cara kerjanya

test.sh

#!/usr/bin/env bash

if [ $# -ge 3 ]
then
  echo script has at least 3 arguments
fi

menghasilkan output berikut

$ ./test.sh
~
$ ./test.sh 1
~
$ ./test.sh 1 2
~
$ ./test.sh 1 2 3
script has at least 3 arguments
$ ./test.sh 1 2 3 4
script has at least 3 arguments
Taman Brad
sumber
3

Sebagai pengingat kecil, operator tes numerik di Bash hanya bekerja pada bilangan bulat ( -eq, -lt, -ge, dll)

Saya ingin memastikan $ vars saya masuk

var=$(( var + 0 ))

sebelum saya mengujinya, hanya untuk membela terhadap kesalahan "[: integer arg required".

Cwissy
sumber
1
Trik yang rapi, tetapi harap dicatat: karena ketidakmampuan bash untuk menangani float dalam aritmatika, metode ini dapat menyebabkan kesalahan sintaks dan mengembalikan non-nol yang akan menjadi penghalang di mana errexit diaktifkan. var=$(printf "%.0f" "$var")dapat menangani float tetapi menderita keluar non-nol saat diberi string. Jika Anda tidak keberatan awk, metode ini saya gunakan tampaknya menjadi yang paling kuat untuk menegakkan integer: var=$(<<<"$var" awk '{printf "%.0f", $0}'). Jika var tidak disetel, defaultnya adalah "0". Jika var adalah float, itu dibulatkan ke bilangan bulat terdekat. Nilai negatif juga baik untuk digunakan.
user.friendly
0

validasi fungsi satu liner bash

myFunction() {

    : ${1?"forgot to supply an argument"}
    if [ "$1" -gt "-1" ]; then
        echo hi
    fi

}

tambahkan nama fungsi dan penggunaan

myFunction() {

    : ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage:  ${FUNCNAME[0]} some_integer"}
    if [ "$1" -gt "-1" ]; then
        echo hi
    fi

}

tambahkan validasi untuk memeriksa apakah bilangan bulat

untuk menambahkan validasi tambahan, misalnya untuk memeriksa untuk melihat apakah argumen yang disahkan adalah bilangan bulat, modifikasi validasi satu liner untuk memanggil fungsi validasi:

: ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage:  ${FUNCNAME[0]} some_integer"} && validateIntegers $1 || die "Must supply an integer!"

kemudian, buat fungsi validasi yang memvalidasi argumen, mengembalikan 0 pada keberhasilan, 1 pada kegagalan dan fungsi mati yang membatalkan skrip pada kegagalan

validateIntegers() {

    if ! [[ "$1" =~ ^[0-9]+$ ]]; then
        return 1 # failure
    fi
    return 0 #success

}

die() { echo "$*" 1>&2 ; exit 1; }

Lebih sederhana - cukup gunakan set -u

set -u memastikan bahwa setiap variabel yang direferensikan diatur saat digunakan, jadi atur dan lupakan saja

myFunction() {
    set -u
    if [ "$1" -gt "-1" ]; then
        echo hi
    fi

}
AndrewD
sumber