Bagaimana cara menulis skrip bash yang mengambil argumen input opsional?

471

Saya ingin skrip saya dapat mengambil input opsional,

misalnya skrip saya saat ini

#!/bin/bash
somecommand foo

tapi saya ingin mengatakan:

#!/bin/bash
somecommand  [ if $1 exists, $1, else, foo ]
Abe
sumber
3
Bash atau POSIX? Dengan Bash, ada lebih banyak kemungkinan
user123444555621
@ Pumbaa80 bash - Saya telah memperbarui tag.
Abe

Jawaban:

707

Anda dapat menggunakan sintaks nilai default:

somecommand ${1:-foo}

Akan di atas, seperti yang dijelaskan dalam Manual Referensi Bash - 3.5.3 Ekspansi Parameter Shell [penekanan tambang]:

Jika parameter tidak disetel atau nol , perluasan kata diganti. Jika tidak, nilai parameter diganti.

Jika Anda hanya ingin mengganti nilai default jika parameter tidak disetel (tetapi tidak jika itu nol, misalnya tidak jika itu adalah string kosong), gunakan sintaks ini sebagai gantinya:

somecommand ${1-foo}

Lagi dari Bash Reference Manual - 3.5.3 Ekspansi Parameter Shell :

Menghilangkan titik dua menghasilkan tes hanya untuk parameter yang tidak disetel. Dengan kata lain, jika titik dua dimasukkan, operator menguji keberadaan parameter dan nilainya tidak nol; jika titik dua dihilangkan, operator hanya menguji keberadaannya.

Itay Perl
sumber
53
Harap perhatikan perbedaan semantik antara perintah di atas, "kembali foojika $1tidak disetel atau string kosong ", dan ${1-foo}, "kembali foojika $1tidak disetel".
l0b0
12
Bisakah Anda jelaskan mengapa ini berhasil? Khususnya, apa fungsi / tujuan dari ':' dan '-'?
jwien001
8
@ jwein001: Dalam jawaban yang disampaikan di atas, operator substitusi digunakan untuk mengembalikan nilai default jika variabel tidak terdefinisi. Secara khusus, logikanya adalah "Jika $ 1 ada dan tidak nol, kembalikan nilainya; jika tidak, kembalikan foo." Usus besar adalah opsional. Jika dihilangkan, ubah "ada dan bukan nol" menjadi "ada". Tanda minus menentukan untuk mengembalikan foo tanpa menetapkan $ 1 sama dengan 'foo'. Operator substitusi adalah subkelas dari operator ekspansi. Lihat bagian 6.1.2.1 dari Scripting Klasik Robbins dan Beebe [O'Reilly] ( shop.oreilly.com/product/9780596005955.do )
Jubbles
5
@Jubbles atau jika Anda tidak ingin membeli seluruh buku untuk referensi sederhana ... tldp.org/LDP/abs/html/parameter-substitution.html
Ohad Schneider
2
Jawaban ini akan lebih baik jika itu menunjukkan bagaimana membuat default menjadi hasil dari menjalankan perintah, seperti yang dilakukan @hagen (meskipun jawaban itu tidak akurat).
sautedman
310

Anda dapat menetapkan nilai default untuk variabel seperti:

somecommand.sh

#!/usr/bin/env bash

ARG1=${1:-foo}
ARG2=${2:-bar}
ARG3=${3:-1}
ARG4=${4:-$(date)}

echo "$ARG1"
echo "$ARG2"
echo "$ARG3"
echo "$ARG4"

Berikut ini beberapa contoh cara kerjanya:

$ ./somecommand.sh
foo
bar
1
Thu Mar 29 10:03:20 ADT 2018

$ ./somecommand.sh ez
ez
bar
1
Thu Mar 29 10:03:40 ADT 2018

$ ./somecommand.sh able was i
able
was
i
Thu Mar 29 10:03:54 ADT 2018

$ ./somecommand.sh "able was i"
able was i
bar
1
Thu Mar 29 10:04:01 ADT 2018

$ ./somecommand.sh "able was i" super
able was i
super
1
Thu Mar 29 10:04:10 ADT 2018

$ ./somecommand.sh "" "super duper"
foo
super duper
1
Thu Mar 29 10:05:04 ADT 2018

$ ./somecommand.sh "" "super duper" hi you
foo
super duper
hi
you
Taman Brad
sumber
2
Ah, baiklah. Saya -bingung (apakah dinegasikan?).
Raffi Khatchadourian
5
Tidak - itu hanya cara aneh yang dimiliki bash dalam melakukan tugas. Saya akan menambahkan beberapa contoh lagi untuk memperjelas hal ini ... terima kasih!
Brad Parks
44
if [ ! -z $1 ] 
then 
    : # $1 was given
else
    : # $1 was not given
fi
Irit Katriel
sumber
1
Secara teknis, jika Anda memasukkan string kosong '' yang mungkin dianggap sebagai parameter, tetapi cek Anda akan melewatinya. Dalam hal ini $ # akan mengatakan berapa banyak parameter yang diberikan
vmpstr
18
-nsama dengan ! -z.
l0b0
Saya mendapatkan hasil yang berbeda menggunakan -ndan ! -zjadi saya akan mengatakan itu tidak terjadi di sini.
Eliezer
karena Anda gagal mengutip variabel, [ -n $1 ] akan selalu benar . Jika Anda menggunakan bash, [[ -n $1 ]]akan berperilaku seperti yang Anda harapkan, jika tidak Anda harus mengutip[ -n "$1" ]
glenn jackman
21

Anda dapat memeriksa jumlah argumen dengan $#

#!/bin/bash
if [ $# -ge 1 ]
then
    $1
else
    foo
fi
Dennis
sumber
10

jangan lupa, jika variabelnya $ 1 .. $ n Anda perlu menulis ke variabel biasa untuk menggunakan substitusi

#!/bin/bash
NOW=$1
echo  ${NOW:-$(date +"%Y-%m-%d")}
hagen
sumber
2
Jawaban Brad di atas membuktikan bahwa variabel argumen juga dapat diganti tanpa vars menengah.
Vadzim
2
+1 untuk mencatat cara menggunakan perintah seperti tanggal sebagai default, bukan nilai tetap. Ini juga memungkinkan:DAY=${1:-$(date +%F -d "yesterday")}
Garren S
3

Untuk beberapa argumen opsional , dengan analogi dengan lsperintah yang dapat mengambil satu atau lebih file atau secara default mendaftar semua yang ada di direktori saat ini:

if [ $# -ge 1 ]
then
    files="$@"
else
    files=*
fi
for f in $files
do
    echo "found $f"
done

Sayangnya, tidak berfungsi dengan benar untuk file dengan spasi di path. Belum menemukan cara membuatnya.

Jesse Glick
sumber
2

Ini memungkinkan nilai default untuk opsional 1st arg, dan mempertahankan beberapa arg.

 > cat mosh.sh
   set -- ${1:-xyz} ${@:2:$#} ; echo $*    
 > mosh.sh
   xyz
 > mosh.sh  1 2 3
   1 2 3 
mosh
sumber
1

Dimungkinkan untuk menggunakan substitusi variabel untuk menggantikan nilai tetap atau perintah (seperti date) untuk argumen. Jawabannya sejauh ini berfokus pada nilai-nilai tetap, tetapi inilah yang saya gunakan untuk menjadikan tanggal sebagai argumen opsional:

~$ sh co.sh
2017-01-05

~$ sh co.sh 2017-01-04
2017-01-04

~$ cat co.sh

DAY=${1:-$(date +%F -d "yesterday")}
echo $DAY
Garren S
sumber