Como escrever um script bash que aceita argumentos de entrada opcionais?

471

Quero que meu script possa receber uma entrada opcional,

por exemplo, atualmente meu script é

#!/bin/bash
somecommand foo

mas gostaria de dizer:

#!/bin/bash
somecommand  [ if $1 exists, $1, else, foo ]
Abe
fonte
3
Bash ou POSIX? Com o Bash, existem mais possibilidades
user123444555621 17/02/2012
@ Pumbaa80 bash - atualizei as tags.
Abe

Respostas:

706

Você pode usar a sintaxe do valor padrão:

somecommand ${1:-foo}

O descrito acima, conforme descrito no Manual de Referência do Bash - 3.5.3 Expansão dos parâmetros do shell [ênfase minha]:

Se o parâmetro estiver desativado ou nulo , a expansão da palavra será substituída. Caso contrário, o valor do parâmetro é substituído.

Se você deseja substituir apenas um valor padrão se o parâmetro não estiver definido (mas não se for nulo, por exemplo, se for uma sequência vazia), use esta sintaxe:

somecommand ${1-foo}

Novamente do Manual de Referência do Bash - 3.5.3 Expansão dos parâmetros do shell :

A omissão dos dois pontos resulta em um teste apenas para um parâmetro não definido. Em outras palavras, se os dois pontos estiverem incluídos, o operador testa a existência dos dois parâmetros e se seu valor não é nulo; se os dois pontos forem omitidos, o operador testa apenas a existência.

Itay Perl
fonte
52
Observe a diferença semântica entre o comando acima, "retornar foose $1não estiver definido ou uma string vazia " e ${1-foo}"retornar foose $1não estiver definido".
L0b0
12
Você pode explicar por que isso funciona? Especialmente, qual é a função / finalidade do ':' e '-'?
precisa saber é o seguinte
8
@ jwein001: na resposta enviada acima, um operador de substituição é usado para retornar um valor padrão se a variável não estiver definida. Especificamente, a lógica é "Se $ 1 existe e não é nulo, retorne seu valor; caso contrário, retorne foo". O cólon é opcional. Se omitido, a alteração "existe e não é nula" para apenas "existe". O sinal de menos especifica retornar foo sem definir $ 1 igual a 'foo'. Operadores de substituição são uma subclasse de operadores de expansão. Consulte a seção 6.1.2.1 de Script de shell clássico de Robbins e Beebe [O'Reilly] ( shop.oreilly.com/product/9780596005955.do )
Jubbles
5
@Jubbles ou se você não quiser comprar um livro inteiro para uma simples referência ... tldp.org/LDP/abs/html/parameter-substitution.html
Ohad Schneider
2
Essa resposta seria ainda melhor se mostrasse como tornar o padrão o resultado da execução de um comando, como o @hagen faz (embora essa resposta seja deselegante).
21817 Sautedman
310

Você pode definir um valor padrão para uma variável assim:

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"

Aqui estão alguns exemplos de como isso funciona:

$ ./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
Brad Parks
fonte
2
Ah ok. O -mim confuso (é negado?).
Raffi Khatchadourian 28/03
5
Não - essa é apenas uma maneira estranha de o bash fazer a tarefa. Vou adicionar mais alguns exemplos para esclarecer um pouco ... obrigado!
Brad Parks
44
if [ ! -z $1 ] 
then 
    : # $1 was given
else
    : # $1 was not given
fi
Irit Katriel
fonte
1
Tecnicamente, se você passar uma string vazia '' que pode contar como um parâmetro, mas sua verificação não será atendida. Nesse caso, $ # diria quantos parâmetros foram dados
vmpstr 17/02/2012
18
-né o mesmo que ! -z.
L0b0
Eu obtenho resultados diferentes usando -ne, ! -zportanto, diria que não é o caso aqui.
Eliezer
porque você não conseguiu citar a variável, [ -n $1 ] sempre será verdade . Se você usa o bash, [[ -n $1 ]]irá se comportar conforme o esperado, caso contrário, você deve citar[ -n "$1" ]
glenn jackman 19/03
21

Você pode verificar o número de argumentos com $#

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

por favor não esqueça, se sua variável $ 1 .. $ n você precisa escrever em uma variável regular para usar a substituição

#!/bin/bash
NOW=$1
echo  ${NOW:-$(date +"%Y-%m-%d")}
hagen
fonte
2
A resposta de Brad acima prova que as variáveis ​​de argumento também podem ser substituídas sem vars intermediários.
Vadzim 28/03
2
+1 por observar a maneira de usar um comando como data como o padrão em vez de um valor fixo. Isso também é possível:DAY=${1:-$(date +%F -d "yesterday")}
Garren S
3

Para vários argumentos opcionais , por analogia com o lscomando que pode levar um ou mais arquivos ou, por padrão, lista tudo no diretório atual:

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

Infelizmente, não funciona corretamente para arquivos com espaços no caminho. Ainda não descobri como fazer isso funcionar.

Jesse Glick
fonte
2

Isso permite o valor padrão para o 1º arg opcional e preserva vários args.

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

É possível usar a substituição de variável para substituir um valor fixo ou um comando (como date) por um argumento. As respostas até agora se concentraram em valores fixos, mas é isso que eu costumava fazer da data um argumento opcional:

~$ 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
fonte