Як написати скрипт bash, який бере необов'язкові вхідні аргументи?


471

Я хочу, щоб мій сценарій міг взяти необов'язковий вклад,

наприклад, зараз мій сценарій є

#!/bin/bash
somecommand foo

але я хотів би сказати:

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

3
Bash або POSIX? У Bash є більше можливостей
user123444555621

@ Pumbaa80 bash - я оновив теги.
Абе


Відповіді:


705

Ви можете використовувати синтаксис значення за замовчуванням:

somecommand ${1:-foo}

Вищенаведене буде, як описано в Довідковому посібнику Баша - Розширення параметрів оболонки 3.5.3 [моє наголос]:

Якщо параметр не встановлений або недійсний , розширення слова замінено. В іншому випадку значення параметра замінено.

Якщо ви хочете замінити значення за замовчуванням лише у випадку, якщо параметр не встановлено (але не, якщо він є нульовим, наприклад, ні, якщо це порожній рядок), використовуйте замість цього синтаксис:

somecommand ${1-foo}

Знову з Довідкового керівництва Bash - Розширення параметрів оболонки 3.5.3 :

Пропускання товстої кишки призводить до тестування лише для параметра, який не встановлений. По-іншому, якщо двокрапка включена, оператор перевіряє наявність обох параметрів і на те, що його значення не є нульовим; якщо товсту кишку опущено, оператор перевіряє лише наявність.


52
Зверніть увагу на семантичну різницю між вищевказаною командою "повернути, fooякщо $1не встановлено, або порожній рядок ", і ${1-foo}"повернути, fooякщо $1не встановлено".
l0b0

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 (хоча ця відповідь не є елегантною).
сотман

309

Ви можете встановити значення за замовчуванням для такої змінної:

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
Ні - це просто дивний спосіб, коли Баш виконує завдання. Додам ще кілька прикладів, щоб це трохи уточнити ... дякую!
Бред Паркс

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

1
Технічно, якщо ви перейдете в порожній рядок '', який може вважатися параметром, але ваш чек буде пропущений. У цьому випадку $ # скаже, скільки було задано параметрів
vmpstr

18
-nте саме, що ! -z.
l0b0

Я отримую різні результати використання -nі ! -zтому я хотів би сказати , що це не той випадок.
Елієзер

тому що вам не вдалося процитувати змінну, [ -n $1 ] завжди буде правдою . Якщо ви використовуєте bash, [[ -n $1 ]]буде вести себе так, як ви очікували, інакше ви повинні цитувати[ -n "$1" ]
glenn jackman

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 - відзначити спосіб використання такої команди, як дата, як за замовчуванням замість фіксованого значення. Це також можливо:DAY=${1:-$(date +%F -d "yesterday")}
Гаррен S

3

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

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

Не працює належним чином для файлів з пробілами в шляху, на жаль. Ще не придумали, як змусити цю роботу.


2

Це дозволяє за замовчуванням значення для необов'язкового першого аргументу та зберігає кілька аргументів.

 > 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.