İsteğe bağlı giriş argümanları alan bir bash betiği nasıl yazılır?


471

Betiğimin isteğe bağlı bir girdi alabilmesini istiyorum,

örneğin şu anda benim senaryom

#!/bin/bash
somecommand foo

ama şunu söylemek isterim:

#!/bin/bash
somecommand  [ if $1 exists, $1, else, foo ]

3
Bash mi POSIX mi? Bash ile daha fazla olasılık var
user123444555621

@ Pumbaa80 bash - Etiketleri güncelledim.
Abe


Yanıtlar:


706

Varsayılan değer sözdizimini kullanabilirsiniz:

somecommand ${1:-foo}

Yukarıdakiler, Bash Referans Kılavuzu - 3.5.3 Kabuk Parametre Genişletme [vurgu mayını] ' nda açıklandığı gibi olacaktır :

Parametre ayarlanmamış veya null ise , sözcüğün genişletilmesi değiştirilir. Aksi takdirde, parametrenin değeri değiştirilir.

Yalnızca parametre ayarlanmadıysa (ancak boş değilse, örneğin boş bir dize değilse değil) varsayılan bir değeri değiştirmek istiyorsanız, bunun yerine bu sözdizimini kullanın:

somecommand ${1-foo}

Yine Bash Referans Kılavuzundan - 3.5.3 Kabuk Parametre Genişletme :

İki nokta üst üste işareti atlandığında yalnızca ayarlanmamış bir parametre için sınama yapılır. Kolon dahil edilirse, operatör her iki parametrenin varlığını ve değerinin boş olmadığını test eder; iki nokta üst üste işareti atlanırsa, operatör yalnızca varlığını test eder.


52
"Geriye dönüş yukarıdaki komutu arasındaki semantik fark unutmayın fooeğer $1ayarlanmazsa veya boş dize " ve ${1-foo}"geri dönüş, fooeğer $1ayarlanmazsa".
l0b0

12
Bunun neden işe yaradığını açıklayabilir misiniz? Özellikle, ':' ve '-' nin işlevi / amacı nedir?
jwien001

8
@ jwein001: Yukarıda verilen cevapta, değişken tanımlanmamışsa varsayılan değeri döndürmek için bir ikame operatörü kullanılır. Özellikle, mantık "$ 1 varsa ve null değilse, değerini döndürün; aksi halde foo döndürün." İki nokta üst üste isteğe bağlıdır. Atlanırsa "var ve boş değil" değerini yalnızca "var" olarak değiştirin. Eksi işareti, $ 1'i 'foo' değerine eşitlemeden foo döndürmeyi belirtir. İkame işleçleri, genişletme işleçlerinin bir alt sınıfıdır. Robbins ve Beebe'nin Klasik Kabuk Betiği [O'Reilly] ' nin 6.1.2.1 bölümüne bakın ( shop.oreilly.com/product/9780596005955.do )
Jubbles

5
@Jubbles veya basit bir referans için bir kitabın tamamını satın almak istemiyorsanız ... tldp.org/LDP/abs/html/parameter-substitution.html
Ohad Schneider

2
Bu yanıt, @hagen'in yaptığı gibi, bir komutun çalıştırılmasının sonucu olarak varsayılanın nasıl yapılacağını gösterdiyse daha da iyi olurdu (bu cevap yetersiz olsa da).
sautedman

310

Şöyle bir değişken için varsayılan bir değer ayarlayabilirsiniz:

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"

Bunun nasıl çalıştığına dair bazı örnekler:

$ ./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

2
Ah tamam. -(Bu negated nedir?) Beni karıştı.
Raffi Khatchadourian

5
Hayır - bu bash'ın görevi yerine getirmesinin garip bir yolu. Bunu biraz açıklığa kavuşturmak için birkaç örnek daha ekleyeceğim ... teşekkürler!
Brad Parks

44
if [ ! -z $1 ] 
then 
    : # $1 was given
else
    : # $1 was not given
fi

1
Teknik olarak, boş bir dize geçirirseniz '' parametre olarak sayılabilir, ancak çekiniz onu özleyecektir. Bu durumda $ #, kaç parametre verildiğini
söyler

18
-nile aynıdır ! -z.
l0b0

Kullanarak farklı sonuçlar elde ediyorum -nve ! -zbu yüzden burada böyle olmadığını söyleyebilirim.
Eliezer

çünkü değişkeni alıntılayamazsınız, [ -n $1 ] her zaman doğrudur . Eğer bash kullanırsanız, [[ -n $1 ]]beklediğiniz gibi davranacaktır, aksi takdirde alıntı yapmalısınız[ -n "$1" ]
glenn jackman

21

İle argüman sayısını kontrol edebilirsiniz $#

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

10

Unutmayın, eğer değişkeni $ 1 .. $ n ise ikameyi kullanmak için normal bir değişkene yazmanız gerekir

#!/bin/bash
NOW=$1
echo  ${NOW:-$(date +"%Y-%m-%d")}

2
Brad'in yukarıdaki cevabı , argüman değişkenlerinin ara değişkenler olmadan da ikame edilebileceğini kanıtlıyor.
Vadzim

2
Tarih gibi bir komutu sabit değer yerine varsayılan olarak kullanmanın yolunu not ettiğiniz için +1. Bu da mümkündür:DAY=${1:-$(date +%F -d "yesterday")}
Garren S

3

İsteğe bağlı çoklu argümanlar için, lsbir veya daha fazla dosya alabilen komutla benzer şekilde veya varsayılan olarak geçerli dizindeki her şeyi listeler:

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

Ne yazık ki yoldaki boşlukları olan dosyalar için düzgün çalışmıyor. Bunu nasıl çalıştıracağını henüz çözemedim.


2

Bu, isteğe bağlı 1. bağımsız değişken için varsayılan değere izin verir ve birden çok bağımsız değişkeni korur.

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

1

Değişken ikamesi, sabit bir değeri veya datebir argümanın komutunu (gibi ) değiştirmek için kullanılabilir. Şimdiye kadar cevaplar sabit değerlere odaklandı, ancak tarihi isteğe bağlı bir argüman yapmak için kullandığım şey bu:

~$ 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.