Estou tentando aprender como usar getopts para que eu possa ter scripts com entrada analisada (embora eu ache que getopts poderia ser melhor). Estou tentando apenas escrever um script simples para retornar as porcentagens de uso da partição. O problema é que uma das minhas funções bash não parece gostar que eu faça referência $1
como uma variável dentro da função. A razão pela qual faço referência $1
é porque a get_percent
função pode receber um ponto de montagem como um argumento opcional para exibir em vez de todos os pontos de montagem.
O roteiro
#!/usr/bin/bash
set -e
set -u
set -o pipefail
get_percent(){
if [ -n "$1" ]
then
df -h $1 | tail -n +2 | awk '{ print $1,"\t",$5 }'
else
df -h | tail -n +2 | awk '{ print $1,"\t",$5 }'
fi
}
usage(){
echo "script usage: $(basename $0) [-h] [-p] [-m mount_point]" >&2
}
# If the user doesn't supply any arguments, we run the script as normal
if [ $# -eq 0 ];
then
get_percent
exit 0
fi
# ...
A saída
$ bash thing.sh
thing.sh: line 8: $1: unbound variable
$ bash -x thing.sh
+ set -e
+ set -u
+ set -o pipefail
+ '[' 0 -eq 0 ']'
+ get_percent
thing.sh: line 8: $1: unbound variable
set -u
irá abortar exatamente como você descreve se você referenciar uma variável que não foi definida. Você está invocando seu script sem argumentos, entãoget_percent
está sendo invocado sem argumentos, fazendo$1
com que não seja definido.Verifique isso antes de invocar sua função ou use expansões padrão (
${1-default}
se expandirá paradefault
se ainda não estiver definido para outra coisa).Este é o efeito de
set -u
.Você pode verificar
$#
dentro da função e evitar fazer referência$1
se ela não estiver definida.Com
$#
você pode acessar o número de parâmetros. No contexto global é o número de parâmetros para o script, em uma função é o número de parâmetros para a função.No contexto da pergunta, é
Observe que você tem que usar
[ $# -ge 1 ] && [ -n "$1" ]
e não[ $# -ge 1 -a -n "$1" ]
, porque isso primeiro avaliaria$1
e depois verificaria$#
.Com "set -u" no script, qualquer referência a uma variável não definida causará um erro, principalmente testando se ela possui um valor, que é o que o script está fazendo.
A função a seguir testará a variável não configurada sem desarmar o set -u:
Usando isso:
if:IsSet someVariableName || echo "someVariableName is not set"
Quanto à função real, teste se um argumento foi passado, não se está vazio. Isso evitará o problema da variável não definida sem que você execute etapas especiais, como testar se a variável tem um valor.
BTW: Dois pontos em um nome de função é apenas um caractere. É válido em um nome de função no Bash, assim como %, }, {, [ e vários outros :-)
Sendo assim,
bash
você pode contornar a verificação de$1
estar definido e apenas usar"$@"
($1
é o primeiro parâmetro,$@
são todos eles; quando aspas duplas, desaparece completamente se não tiver valores, o que evita que seja capturado porset -u
):Eu também ajustei o resto da linha um pouco para que você não obtenha {space}{tab}{space} entre os dois valores que você produz, mas em vez disso você obtém apenas um {tab}. Se você realmente deseja os dois espaços invisíveis, altere o
awk
para usarprintf "%s \t %s\n", $1, $5
.Outras respostas mencionaram que este é o efeito de
set -u
. Nenhuma das outras respostas mencionou queset -u
pode ser revertida comset +u
: