Как написать скрипт bash, который принимает необязательные входные аргументы?

471

Я хочу, чтобы мой сценарий мог принимать необязательный ввод,

например, в настоящее время мой сценарий

#!/bin/bash
somecommand foo

но я бы хотел сказать:

#!/bin/bash
somecommand  [ if $1 exists, $1, else, foo ]
Abe
источник
3
Баш или POSIX? С Bash, есть больше возможностей
user123444555621
@ Pumbaa80 bash - я обновил теги.
Абэ
1
См. Также unix.stackexchange.com/questions/122845/…
Вадим

Ответы:

707

Вы можете использовать синтаксис значения по умолчанию:

somecommand ${1:-foo}

Выше будет, как описано в Справочном руководстве Bash - 3.5.3 Расширение параметров оболочки [выделено мной]:

Если параметр не установлен или ноль , расширение слова заменяется. В противном случае значение параметра подставляется.

Если вы хотите заменить значение по умолчанию только в том случае, если параметр не установлен (но не в том случае, если он нулевой, например, если это не пустая строка), используйте вместо этого следующий синтаксис:

somecommand ${1-foo}

Снова из Справочного руководства Bash - 3.5.3 Расширение параметров оболочки :

Пропуск двоеточия приводит к проверке только для неустановленного параметра. Другими словами, если двоеточие включено, оператор проверяет наличие как параметра, так и того, что его значение не равно нулю; если двоеточие опущено, оператор проверяет только наличие.

Итай Перл
источник
53
Обратите внимание на семантическую разницу между приведенной выше командой: «вернуть, fooесли $1не задано или пустую строку », и ${1-foo}«вернуть, fooесли $1не задана».
10
12
Можете ли вы объяснить, почему это работает? Специально, какова функция / назначение ':' и '-'?
jwien001
8
@ jwein001: в ответе, представленном выше, оператор замены используется для возврата значения по умолчанию, если переменная не определена. В частности, логика такова: «Если $ 1 существует и не равен нулю, верните его значение; в противном случае верните foo». Двоеточие необязательно. Если оно опущено, измените «существует и не является нулевым» на «только существует». Знак минус указывает на возвращение foo без установки $ 1 равным 'foo'. Операторы подстановки являются подклассом операторов раскрытия. См. Раздел 6.1.2.1 « Классического сценария сценариев Роббинса и Биба» [O'Reilly] ( shop.oreilly.com/product/9780596005955.do )
Jubbles,
5
@Jubbles или если вы не хотите покупать целую книгу для простого ознакомления ... tldp.org/LDP/abs/html/parameter-substitution.html
Охад Шнайдер,
2
Этот ответ был бы еще лучше, если бы он показал, как сделать значение по умолчанию результатом выполнения команды, как это делает @hagen (хотя этот ответ не элегантен).
sautedman
310

Вы можете установить значение по умолчанию для переменной следующим образом:

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"

Вот несколько примеров того, как это работает:

$ ./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
Ах хорошо. -Меня смутило (это отрицается?).
Раффи Хачадурян
5
Нет - это просто странный способ, которым bash выполняет задания. Я добавлю еще несколько примеров, чтобы прояснить это немного ... спасибо!
Брэд Паркс
44
if [ ! -z $1 ] 
then 
    : # $1 was given
else
    : # $1 was not given
fi
Ирит Катриэль
источник
1
Технически, если вы передадите пустую строку '', которая может считаться параметром, но ваша проверка пропустит ее. В этом случае $ # скажет, сколько параметров было задано
vmpstr
18
-nтак же, как ! -z.
10
Я получаю разные результаты, -nи ! -zпоэтому я бы сказал, что это не так.
Элиэзер
потому что вы не смогли процитировать переменную, [ -n $1 ] всегда будет истина . Если вы используете bash, [[ -n $1 ]]будете вести себя так, как вы ожидаете, в противном случае вы должны процитировать[ -n "$1" ]
Гленн Джекман
21

Вы можете проверить количество аргументов с $#

#!/bin/bash
if [ $# -ge 1 ]
then
    $1
else
    foo
fi
Деннис
источник
10

пожалуйста, не забывайте, если его переменная $ 1 .. $ n, вам нужно записать в обычную переменную, чтобы использовать подстановку

#!/bin/bash
NOW=$1
echo  ${NOW:-$(date +"%Y-%m-%d")}
хаген
источник
2
Ответ Брэда выше доказывает, что переменные аргумента также могут быть заменены без промежуточных переменных.
Вадим
2
+1 за то, что вы отметили способ использовать команду типа date в качестве значения по умолчанию вместо фиксированного значения. Это также возможно:DAY=${1:-$(date +%F -d "yesterday")}
Гаррен С
3

Для необязательных множественных аргументов по аналогии с lsкомандой, которая может принимать один или несколько файлов, или по умолчанию перечисляется все в текущем каталоге:

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

Не работает корректно для файлов с пробелами в пути, увы. Пока не разобрался, как заставить это работать.

Джесси Глик
источник
2

Это позволяет использовать значение по умолчанию для необязательного 1-го аргумента и сохраняет несколько аргументов.

 > cat mosh.sh
   set -- ${1:-xyz} ${@:2:$#} ; echo $*    
 > mosh.sh
   xyz
 > mosh.sh  1 2 3
   1 2 3 
мош
источник
1

Можно использовать подстановку переменных для замены фиксированного значения или команды (например date) для аргумента. До сих пор ответы были сосредоточены на фиксированных значениях, но это то, что я использовал, чтобы сделать дату необязательным аргументом:

~$ 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
Гаррен С
источник